source: trunk/src/os2ahci/atapi.c@ 209

Last change on this file since 209 was 209, checked in by David Azarewicz, 4 years ago

Debugging support changes.

File size: 15.5 KB
Line 
1/**
2 * atapi.c - ATAPI command processing
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
7 *
8 * Authors: Christian Mueller, Markus Thielen
9 *
10 * Parts copied from/inspired by the Linux AHCI driver;
11 * those parts are (c) Linux AHCI/ATA maintainers
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#include "os2ahci.h"
29#include "ata.h"
30#include "atapi.h"
31
32/* need this for the SCSI status block */
33#include <Dev32scsi.h>
34
35static void atapi_req_sense_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb);
36static int atapi_pad_cdb(u8 *cmd_in, u16 cmd_in_len, u8 *cmd_out, u16 *cmd_out_len);
37
38/******************************************************************************
39 * Get device or media geometry. This function is not expected to be called.
40 */
41int atapi_get_geometry(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
42{
43 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_get_geometry called\n");
44 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
45 return(-1);
46}
47
48/******************************************************************************
49 * Test whether unit is ready. This function is not expected to be called.
50 */
51int atapi_unit_ready(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
52{
53 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_unit_ready called\n");
54 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
55 return(-1);
56}
57
58/******************************************************************************
59 * Read sectors from AHCI device.
60 */
61int atapi_read(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
62{
63 IORB_EXECUTEIO *io = (IORB_EXECUTEIO *)pIorb;
64 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);
65 ATAPI_CDB_12 cdb;
66 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
67 USHORT count = io->BlockCount - io->BlocksXferred;
68 USHORT sg_indx;
69 USHORT sg_cnt;
70 int p = iorb_unit_port(pIorb);
71 int d = iorb_unit_device(pIorb);
72 int rc;
73
74 if (io->BlockCount == 0)
75 {
76 /* NOP; return -1 without error in IORB to indicate success */
77 return(-1);
78 }
79
80 if (add_workspace(pIorb)->unaligned)
81 {
82 /* unaligned S/G addresses present; need to use double buffers */
83 return(atapi_read_unaligned(pIorb, slot));
84 }
85
86 /* translate read command to SCSI/ATAPI READ12 command.
87 * READ12 seems to be the most supported READ variant - according to MMC,
88 * and it's enough even for BluRay.
89 */
90 memset(&cdb, 0x00, sizeof(cdb));
91 cdb.cmd = ATAPI_CMD_READ_12;
92 SET_CDB_32(cdb.lba, io->RBA + io->BlocksXferred);
93
94 DPRINTF(DBG_DETAILED, DBG_PREFIX": atapi_read\n");
95
96 do {
97 /* update sector count (might have been updated due to S/G limitations) */
98 SET_CDB_32(cdb.trans_len, count);
99
100 /* update S/G count and index */
101 sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize);
102 sg_cnt = io->cSGList - sg_indx;
103
104 /* issue command */
105 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
106 AP_ATAPI_CMD, (void *) &cdb, sizeof(cdb),
107 AP_SGLIST, pSGList + sg_indx, sg_cnt,
108 AP_DEVICE, 0x40,
109 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
110 AP_END);
111
112 if (rc > 0)
113 {
114 /* couldn't map all S/G elements */
115 ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
116 }
117 } while (rc > 0 && sg_cnt > 0);
118
119 if (rc == 0)
120 {
121 add_workspace(pIorb)->blocks = count;
122 add_workspace(pIorb)->ppfunc = ata_read_pp;
123 }
124 else if (rc > 0)
125 {
126 iorb_seterr(pIorb, IOERR_CMD_SGLIST_BAD);
127 }
128 else if (rc == ATA_CMD_UNALIGNED_ADDR)
129 {
130 /* unaligned S/G addresses detected; need to use double buffers */
131 add_workspace(pIorb)->unaligned = 1;
132 return(atapi_read_unaligned(pIorb, slot));
133 }
134 else
135 {
136 iorb_seterr(pIorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
137 }
138
139 return(rc);
140}
141
142/******************************************************************************
143 * Read sectors from AHCI device with unaligned S/G element addresses. AHCI
144 * only allows aligned S/G addresses while OS/2 doesn't have these kind of
145 * restrictions. This doesn't happen very often but when it does, we need to
146 * use a transfer buffer and copy the data manually.
147 */
148int atapi_read_unaligned(IORBH *pIorb, int slot)
149{
150 IORB_EXECUTEIO *io = (IORB_EXECUTEIO *)pIorb;
151 ADD_WORKSPACE *aws = add_workspace(pIorb);
152 ATAPI_CDB_12 cdb;
153 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
154 int p = iorb_unit_port(pIorb);
155 int d = iorb_unit_device(pIorb);
156 int rc;
157
158 /* translate read command to SCSI/ATAPI READ12 command.
159 * READ12 seems to be the most supported READ variant - according to MMC,
160 * and it's enough even for BluRay.
161 */
162 memset(&cdb, 0x00, sizeof(cdb));
163 cdb.cmd = ATAPI_CMD_READ_12;
164 SET_CDB_32(cdb.lba, io->RBA + io->BlocksXferred);
165 SET_CDB_32(cdb.trans_len, 1UL);
166
167 ai->ports[p].unaligned_read_count++;
168 DPRINTF(DBG_DETAILED, DBG_PREFIX": atapi_read_unaligned\n");
169
170 /* allocate transfer buffer */
171 if ((aws->buf = MemAlloc(io->BlockSize)) == NULL)
172 {
173 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
174 return(-1);
175 }
176
177 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
178 AP_ATAPI_CMD, (void *) &cdb, sizeof(cdb),
179 AP_VADDR, (void *) aws->buf, io->BlockSize,
180 AP_DEVICE, 0x40,
181 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
182 AP_END);
183
184 if (rc == 0)
185 {
186 add_workspace(pIorb)->blocks = 1;
187 add_workspace(pIorb)->ppfunc = ata_read_pp;
188
189 }
190 else if (rc > 0)
191 {
192 iorb_seterr(pIorb, IOERR_CMD_SGLIST_BAD);
193
194 }
195 else
196 {
197 iorb_seterr(pIorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
198 }
199
200 return(rc);
201}
202
203/******************************************************************************
204 * Verify readability of sectors on AHCI device. This function is not expected
205 * to be called.
206 */
207int atapi_verify(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
208{
209 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_verify called\n");
210 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
211 return(-1);
212}
213
214/******************************************************************************
215 * Write sectors to AHCI device. This function is not expected to be called.
216 */
217int atapi_write(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
218{
219 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_write called\n");
220 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
221 return(-1);
222}
223
224/******************************************************************************
225 * Execute ATAPI command.
226 */
227int atapi_execute_cdb(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
228{
229 IORB_ADAPTER_PASSTHRU *pt = (IORB_ADAPTER_PASSTHRU *)pIorb;
230 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(pt->f16SGList);
231 int rc;
232 u8 cdb[ATAPI_MAX_CDB_LEN];
233 u16 cdb_len;
234
235 if (pt->ControllerCmdLen > ATAPI_MAX_CDB_LEN)
236 {
237 iorb_seterr(pIorb, IOERR_CMD_SYNTAX);
238 return -1;
239 }
240 /* AHCI requires 12 or 16 byte commands */
241 atapi_pad_cdb(Far16ToFlat(pt->f16ControllerCmd), pt->ControllerCmdLen, cdb, &cdb_len);
242
243 if (cdb[0] == 0x12 || cdb[0] == 0x5a)
244 {
245 /* somebody sets the direction flag incorrectly for those commands */
246 pt->Flags |= PT_DIRECTION_IN;
247 }
248
249 /* we do not perform the S/G limitation recovery loop here:
250 * "ADDs are not required to iterate commands through the CDB PassThru
251 * mechanism:" -- Storage Device Driver Reference, Scatter/Gather Lists
252 */
253 rc = ata_cmd(ad_infos + iorb_unit_adapter(pIorb), iorb_unit_port(pIorb),
254 iorb_unit_device(pIorb), slot, ATA_CMD_PACKET,
255 AP_ATAPI_CMD, (void *)cdb, cdb_len,
256 AP_SGLIST, pSGList, pt->cSGList,
257 AP_WRITE, !(pt->Flags & PT_DIRECTION_IN),
258 AP_FEATURES, ATAPI_FEAT_DMA,
259 AP_FEATURES, (pt->Flags & PT_DIRECTION_IN) ? ATAPI_FEAT_DMA_TO_HOST : 0,
260 AP_END);
261
262 if (rc)
263 {
264 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
265 }
266
267 return(rc);
268}
269
270
271/******************************************************************************
272 * Request sense information for a failed command.
273 *
274 * NOTE: This function must be called right after an ATAPI command has failed
275 * and before any other commands are queued on the corresponding device.
276 * This function is typically called in the port restart context hook
277 * which is triggered by an AHCI error interrupt.
278 *
279 */
280int atapi_req_sense(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
281{
282 SCSI_STATUS_BLOCK *ssb;
283 ADD_WORKSPACE *aws = add_workspace(pIorb);
284 int rc;
285 u8 cdb[ATAPI_MIN_CDB_LEN];
286 ATAPI_CDB_6 *pcdb = (ATAPI_CDB_6 *) cdb;
287 size_t sense_buf_len = ATAPI_SENSE_LEN;
288
289 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_req_sense\n");
290
291 if ((pIorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
292 pIorb->StatusBlockLen >= sizeof(*ssb) && pIorb->pStatusBlock != 0)
293 {
294 ULONG ulTmp;
295
296 ulTmp = (CastFar16ToULONG(vIorb) & 0xffff0000) + pIorb->pStatusBlock;
297 ssb = (SCSI_STATUS_BLOCK *)Far16ToFlat(CastULONGToFar16(ulTmp));
298
299 /* don't request sense data if caller asked us not to; the flag
300 * STATUS_DISABLE_REQEST_SENSE is not defined in the old DDK we've been
301 * using so we'll use the hard-coded value (0x0008) */
302 if (ssb->Flags & 0x0008U)
303 {
304 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
305 return(-1);
306 }
307
308 /* if the sense buffer requested is larger than our default, adjust
309 * the length accordingly to satisfy the caller's requirements. */
310 if (ssb->f16SenseData != FAR16NULL && ssb->ReqSenseLen > sense_buf_len)
311 {
312 sense_buf_len = ssb->ReqSenseLen;
313 }
314 }
315
316 /* allocate sense buffer in ADD workspace */
317 if ((aws->buf = MemAlloc(sense_buf_len)) == NULL)
318 {
319 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
320 return(-1);
321 }
322 memset(aws->buf, 0x00, sense_buf_len);
323
324 /* prepare request sense command */
325 memset(cdb, 0x00, sizeof(cdb));
326 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
327 pcdb->trans_len = (u8) sense_buf_len;
328
329 aws->ppfunc = atapi_req_sense_pp;
330 rc = ata_cmd(ad_infos + iorb_unit_adapter(pIorb),
331 iorb_unit_port(pIorb),
332 iorb_unit_device(pIorb),
333 slot,
334 ATA_CMD_PACKET,
335 AP_ATAPI_CMD, (void *)cdb, sizeof(cdb),
336 AP_VADDR, (void *)aws->buf, sense_buf_len,
337 AP_FEATURES, ATAPI_FEAT_DMA,
338 AP_END);
339
340 if (rc > 0)
341 {
342 iorb_seterr(pIorb, IOERR_CMD_SGLIST_BAD);
343 }
344 else if (rc < 0)
345 {
346 /* we failed to get info about an error -> return
347 * non specific device error
348 */
349 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
350 }
351
352 return(rc);
353}
354
355/******************************************************************************
356 * Post processing function for ATAPI request sense; examines the sense
357 * data returned and maps sense info to IORB error info.
358 */
359static void atapi_req_sense_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb)
360{
361 SCSI_STATUS_BLOCK *ssb;
362 ADD_WORKSPACE *aws = add_workspace(pIorb);
363 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
364
365 DHEXDUMP(DBG_DETAILED, psd, sizeof(*psd), "sense buffer:\n");
366
367 if ((pIorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
368 pIorb->StatusBlockLen >= sizeof(*ssb) && pIorb->pStatusBlock != 0)
369 {
370 ULONG ulTmp;
371
372 /* copy sense data to IORB */
373 ulTmp = (CastFar16ToULONG(vIorb) & 0xffff0000) + pIorb->pStatusBlock;
374 ssb = (SCSI_STATUS_BLOCK *)Far16ToFlat(CastULONGToFar16(ulTmp));
375 ssb->AdapterErrorCode = 0;
376 ssb->TargetStatus = SCSI_STAT_CHECKCOND;
377 ssb->ResidualLength = 0;
378 memset(ssb->AdapterDiagInfo, 0x00, sizeof(ssb->AdapterDiagInfo));
379
380 if (ssb->f16SenseData != FAR16NULL)
381 {
382 memcpy(Far16ToFlat(ssb->f16SenseData), psd, ssb->ReqSenseLen);
383 ssb->Flags |= STATUS_SENSEDATA_VALID;
384 }
385 pIorb->Status |= IORB_STATUSBLOCK_AVAIL;
386 }
387
388 /* map sense data to some IOERR_ value */
389 switch (ATAPI_GET_SENSE(psd))
390 {
391 case ASENSE_NO_SENSE:
392 case ASENSE_RECOVERED_ERROR:
393 /* no error; this shouldn't happen because we'll only call
394 * atapi_req_sense() if we received an error interrupt */
395 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
396 break;
397
398 case ASENSE_NOT_READY:
399 iorb_seterr(pIorb, IOERR_UNIT_NOT_READY);
400 break;
401
402 case ASENSE_UNIT_ATTENTION:
403 iorb_seterr(pIorb, IOERR_MEDIA_CHANGED);
404 break;
405
406 case ASENSE_MEDIUM_ERROR:
407 iorb_seterr(pIorb, IOERR_MEDIA);
408 break;
409
410 case ASENSE_ILLEGAL_REQUEST:
411 iorb_seterr(pIorb, IOERR_CMD_SYNTAX);
412 break;
413
414 case ASENSE_DATA_PROTECT:
415 iorb_seterr(pIorb, IOERR_MEDIA_WRITE_PROTECT);
416 break;
417
418 case ASENSE_BLANK_CHECK:
419 iorb_seterr(pIorb, IOERR_MEDIA_NOT_FORMATTED);
420 break;
421
422 case ASENSE_ABORTED_COMMAND:
423 case ASENSE_COPY_ABORTED:
424 iorb_seterr(pIorb, IOERR_CMD_ABORTED);
425 break;
426
427 default:
428 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
429 break;
430 }
431
432 /* mark IORB as complete */
433 aws->complete = 1;
434}
435
436/******************************************************************************
437 * Pad ATAPI commands; AHCI requires ATAPI commands to be either 12 or
438 * 16 bytes in length. This func converts commands that have a 12 byte
439 * equivalent, and pads the others to 12 bytes.
440 * cmd_out buffer is expected to be ATAPI_MAX_CDB_LEN in size.
441 * returns 0 on success, != 0 if the command can't be converted.
442 */
443int atapi_pad_cdb(u8 *cmd_in, u16 cmd_in_len, u8 *cmd_out, u16 *cmd_out_len)
444{
445 ATAPI_CDB_12 *p12;
446 u32 tmp;
447
448 if (cmd_in_len == ATAPI_MIN_CDB_LEN || cmd_in_len == ATAPI_MAX_CDB_LEN)
449 {
450 /* command does not need to be converted */
451 memcpy(cmd_out, cmd_in, cmd_in_len);
452 *cmd_out_len = cmd_in_len;
453 return 0;
454 }
455
456 memset(cmd_out, 0x00, ATAPI_MAX_CDB_LEN);
457 p12 = (ATAPI_CDB_12 *) cmd_out;
458 /* we always convert to 12 byte CDBs */
459 *cmd_out_len = ATAPI_MIN_CDB_LEN;
460
461 /* check if command can be converted */
462 switch (cmd_in[0])
463 {
464 case ATAPI_CMD_READ_6:
465 case ATAPI_CMD_WRITE_6:
466 /* convert from 6 to 12 byte equivalent */
467 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
468 p12->flags = cmd_in[1] & 0xc0; /* 6byte cmds have no flags (FUA etc.) */
469 tmp = GET_CDB_24(cmd_in + 1) & 0x1fffffUL;
470 SET_CDB_32(p12->lba, tmp);
471 SET_CDB_32(p12->trans_len, (cmd_in[4]));
472 p12->control = cmd_in[5];
473 break;
474
475 case ATAPI_CMD_READ_10:
476 case ATAPI_CMD_WRITE_10:
477 /* convert from 10 byte to 12 byte equivalent */
478 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
479 p12->flags = cmd_in[1];
480 p12->control = cmd_in[9];
481 memcpy(p12->lba, cmd_in + 2, 4);
482 tmp = GET_CDB_16(cmd_in + 7);
483 SET_CDB_32(p12->trans_len, tmp);
484 break;
485
486 default:
487 /* pad with zeroes to 12 bytes */
488 memset(cmd_out, 0x00, ATAPI_MIN_CDB_LEN);
489 memcpy(cmd_out, cmd_in, cmd_in_len);
490 break;
491 }
492
493 return 0;
494}
495
Note: See TracBrowser for help on using the repository browser.