source: trunk/src/os2ahci/atapi.c

Last change on this file was 211, checked in by David Azarewicz, 2 years ago

Added workaround to help with VirtualBox issues.
Improved diagnostic messages.
Changed how timeouts are reset and how ctx hooks are triggered.
Added quirk for devices with issues executing some standard commands.
Changed to make /N the default.

File size: 15.5 KB
RevLine 
[205]1/**
[39]2 * atapi.c - ATAPI command processing
3 *
[87]4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
[211]6 * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
[87]7 *
8 * Authors: Christian Mueller, Markus Thielen
9 *
10 * Parts copied from/inspired by the Linux AHCI driver;
[39]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"
[60]30#include "atapi.h"
[39]31
[74]32/* need this for the SCSI status block */
[181]33#include <Dev32scsi.h>
[74]34
[178]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);
[60]37
[39]38/******************************************************************************
[61]39 * Get device or media geometry. This function is not expected to be called.
[39]40 */
[178]41int atapi_get_geometry(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]42{
[209]43 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_get_geometry called\n");
[178]44 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
[39]45 return(-1);
46}
47
48/******************************************************************************
[61]49 * Test whether unit is ready. This function is not expected to be called.
[39]50 */
[178]51int atapi_unit_ready(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]52{
[209]53 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_unit_ready called\n");
[178]54 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
[39]55 return(-1);
56}
57
58/******************************************************************************
59 * Read sectors from AHCI device.
60 */
[178]61int atapi_read(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]62{
[178]63 IORB_EXECUTEIO *io = (IORB_EXECUTEIO *)pIorb;
[204]64 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(io->f16SGList);
[60]65 ATAPI_CDB_12 cdb;
[178]66 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
[60]67 USHORT count = io->BlockCount - io->BlocksXferred;
68 USHORT sg_indx;
69 USHORT sg_cnt;
[178]70 int p = iorb_unit_port(pIorb);
71 int d = iorb_unit_device(pIorb);
[60]72 int rc;
[39]73
[178]74 if (io->BlockCount == 0)
75 {
[110]76 /* NOP; return -1 without error in IORB to indicate success */
77 return(-1);
78 }
79
[178]80 if (add_workspace(pIorb)->unaligned)
81 {
[110]82 /* unaligned S/G addresses present; need to use double buffers */
[178]83 return(atapi_read_unaligned(pIorb, slot));
[110]84 }
85
[60]86 /* translate read command to SCSI/ATAPI READ12 command.
87 * READ12 seems to be the most supported READ variant - according to MMC,
[69]88 * and it's enough even for BluRay.
[60]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
[209]94 DPRINTF(DBG_DETAILED, DBG_PREFIX": atapi_read\n");
[181]95
[60]96 do {
97 /* update sector count (might have been updated due to S/G limitations) */
[178]98 SET_CDB_32(cdb.trans_len, count);
[60]99
100 /* update S/G count and index */
[207]101 sg_indx = SgIndexFromOffset(pSGList, io->cSGList, io->BlocksXferred * io->BlockSize);
[60]102 sg_cnt = io->cSGList - sg_indx;
103
104 /* issue command */
105 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
[178]106 AP_ATAPI_CMD, (void *) &cdb, sizeof(cdb),
107 AP_SGLIST, pSGList + sg_indx, sg_cnt,
[82]108 AP_DEVICE, 0x40,
[64]109 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
[60]110 AP_END);
111
[178]112 if (rc > 0)
113 {
[60]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);
[87]118
[178]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 {
[110]130 /* unaligned S/G addresses detected; need to use double buffers */
[178]131 add_workspace(pIorb)->unaligned = 1;
132 return(atapi_read_unaligned(pIorb, slot));
[60]133 }
[178]134 else
135 {
136 iorb_seterr(pIorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
137 }
[60]138
139 return(rc);
140}
141
[39]142/******************************************************************************
[110]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 */
[178]148int atapi_read_unaligned(IORBH *pIorb, int slot)
[110]149{
[178]150 IORB_EXECUTEIO *io = (IORB_EXECUTEIO *)pIorb;
151 ADD_WORKSPACE *aws = add_workspace(pIorb);
[110]152 ATAPI_CDB_12 cdb;
[178]153 AD_INFO *ai = ad_infos + iorb_unit_adapter(pIorb);
154 int p = iorb_unit_port(pIorb);
155 int d = iorb_unit_device(pIorb);
[110]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);
[112]165 SET_CDB_32(cdb.trans_len, 1UL);
[110]166
[184]167 ai->ports[p].unaligned_read_count++;
[209]168 DPRINTF(DBG_DETAILED, DBG_PREFIX": atapi_read_unaligned\n");
[181]169
[110]170 /* allocate transfer buffer */
[178]171 if ((aws->buf = MemAlloc(io->BlockSize)) == NULL)
172 {
173 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
[110]174 return(-1);
175 }
176
177 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
[178]178 AP_ATAPI_CMD, (void *) &cdb, sizeof(cdb),
179 AP_VADDR, (void *) aws->buf, io->BlockSize,
[110]180 AP_DEVICE, 0x40,
181 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
182 AP_END);
183
[178]184 if (rc == 0)
185 {
186 add_workspace(pIorb)->blocks = 1;
187 add_workspace(pIorb)->ppfunc = ata_read_pp;
[110]188
[178]189 }
190 else if (rc > 0)
191 {
192 iorb_seterr(pIorb, IOERR_CMD_SGLIST_BAD);
[110]193
194 }
[178]195 else
196 {
197 iorb_seterr(pIorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
198 }
[110]199
200 return(rc);
201}
202
203/******************************************************************************
[61]204 * Verify readability of sectors on AHCI device. This function is not expected
205 * to be called.
[39]206 */
[178]207int atapi_verify(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]208{
[209]209 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_verify called\n");
[178]210 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
[39]211 return(-1);
212}
213
214/******************************************************************************
[61]215 * Write sectors to AHCI device. This function is not expected to be called.
[39]216 */
[178]217int atapi_write(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]218{
[209]219 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_write called\n");
[178]220 iorb_seterr(pIorb, IOERR_CMD_NOT_SUPPORTED);
[39]221 return(-1);
222}
223
224/******************************************************************************
225 * Execute ATAPI command.
226 */
[178]227int atapi_execute_cdb(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]228{
[178]229 IORB_ADAPTER_PASSTHRU *pt = (IORB_ADAPTER_PASSTHRU *)pIorb;
[204]230 SCATGATENTRY *pSGList = (SCATGATENTRY*)Far16ToFlat(pt->f16SGList);
[60]231 int rc;
[68]232 u8 cdb[ATAPI_MAX_CDB_LEN];
[65]233 u16 cdb_len;
[60]234
[178]235 if (pt->ControllerCmdLen > ATAPI_MAX_CDB_LEN)
236 {
237 iorb_seterr(pIorb, IOERR_CMD_SYNTAX);
[65]238 return -1;
239 }
[68]240 /* AHCI requires 12 or 16 byte commands */
[204]241 atapi_pad_cdb(Far16ToFlat(pt->f16ControllerCmd), pt->ControllerCmdLen, cdb, &cdb_len);
[65]242
[178]243 if (cdb[0] == 0x12 || cdb[0] == 0x5a)
244 {
[75]245 /* somebody sets the direction flag incorrectly for those commands */
[74]246 pt->Flags |= PT_DIRECTION_IN;
247 }
248
[60]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 */
[178]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,
[67]257 AP_WRITE, !(pt->Flags & PT_DIRECTION_IN),
[69]258 AP_FEATURES, ATAPI_FEAT_DMA,
259 AP_FEATURES, (pt->Flags & PT_DIRECTION_IN) ? ATAPI_FEAT_DMA_TO_HOST : 0,
[60]260 AP_END);
261
[178]262 if (rc)
263 {
264 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
[60]265 }
[87]266
[60]267 return(rc);
[39]268}
269
[60]270
271/******************************************************************************
[39]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 */
[178]280int atapi_req_sense(IORBH FAR16DATA *vIorb, IORBH *pIorb, int slot)
[39]281{
[178]282 SCSI_STATUS_BLOCK *ssb;
283 ADD_WORKSPACE *aws = add_workspace(pIorb);
[60]284 int rc;
[65]285 u8 cdb[ATAPI_MIN_CDB_LEN];
[178]286 ATAPI_CDB_6 *pcdb = (ATAPI_CDB_6 *) cdb;
[77]287 size_t sense_buf_len = ATAPI_SENSE_LEN;
[74]288
[209]289 DPRINTF(DBG_FUNCBEG, DBG_PREFIX": atapi_req_sense\n");
[155]290
[178]291 if ((pIorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
292 pIorb->StatusBlockLen >= sizeof(*ssb) && pIorb->pStatusBlock != 0)
293 {
294 ULONG ulTmp;
[74]295
[178]296 ulTmp = (CastFar16ToULONG(vIorb) & 0xffff0000) + pIorb->pStatusBlock;
297 ssb = (SCSI_STATUS_BLOCK *)Far16ToFlat(CastULONGToFar16(ulTmp));
298
[74]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) */
[178]302 if (ssb->Flags & 0x0008U)
303 {
304 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
[74]305 return(-1);
306 }
[77]307
308 /* if the sense buffer requested is larger than our default, adjust
309 * the length accordingly to satisfy the caller's requirements. */
[204]310 if (ssb->f16SenseData != FAR16NULL && ssb->ReqSenseLen > sense_buf_len)
[178]311 {
[77]312 sense_buf_len = ssb->ReqSenseLen;
313 }
[74]314 }
315
[60]316 /* allocate sense buffer in ADD workspace */
[178]317 if ((aws->buf = MemAlloc(sense_buf_len)) == NULL)
318 {
319 iorb_seterr(pIorb, IOERR_CMD_SW_RESOURCE);
[60]320 return(-1);
321 }
[77]322 memset(aws->buf, 0x00, sense_buf_len);
[60]323
324 /* prepare request sense command */
[65]325 memset(cdb, 0x00, sizeof(cdb));
326 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
[77]327 pcdb->trans_len = (u8) sense_buf_len;
[87]328
[60]329 aws->ppfunc = atapi_req_sense_pp;
[178]330 rc = ata_cmd(ad_infos + iorb_unit_adapter(pIorb),
331 iorb_unit_port(pIorb),
332 iorb_unit_device(pIorb),
[60]333 slot,
334 ATA_CMD_PACKET,
[178]335 AP_ATAPI_CMD, (void *)cdb, sizeof(cdb),
336 AP_VADDR, (void *)aws->buf, sense_buf_len,
[64]337 AP_FEATURES, ATAPI_FEAT_DMA,
[60]338 AP_END);
339
[178]340 if (rc > 0)
341 {
342 iorb_seterr(pIorb, IOERR_CMD_SGLIST_BAD);
343 }
344 else if (rc < 0)
345 {
[60]346 /* we failed to get info about an error -> return
347 * non specific device error
348 */
[178]349 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
[60]350 }
351
352 return(rc);
[39]353}
354
[60]355/******************************************************************************
356 * Post processing function for ATAPI request sense; examines the sense
357 * data returned and maps sense info to IORB error info.
358 */
[178]359static void atapi_req_sense_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb)
[60]360{
[178]361 SCSI_STATUS_BLOCK *ssb;
362 ADD_WORKSPACE *aws = add_workspace(pIorb);
[60]363 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
364
[209]365 DHEXDUMP(DBG_DETAILED, psd, sizeof(*psd), "sense buffer:\n");
[69]366
[178]367 if ((pIorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
368 pIorb->StatusBlockLen >= sizeof(*ssb) && pIorb->pStatusBlock != 0)
369 {
370 ULONG ulTmp;
[74]371
372 /* copy sense data to IORB */
[178]373 ulTmp = (CastFar16ToULONG(vIorb) & 0xffff0000) + pIorb->pStatusBlock;
374 ssb = (SCSI_STATUS_BLOCK *)Far16ToFlat(CastULONGToFar16(ulTmp));
[74]375 ssb->AdapterErrorCode = 0;
376 ssb->TargetStatus = SCSI_STAT_CHECKCOND;
377 ssb->ResidualLength = 0;
378 memset(ssb->AdapterDiagInfo, 0x00, sizeof(ssb->AdapterDiagInfo));
379
[204]380 if (ssb->f16SenseData != FAR16NULL)
[178]381 {
[204]382 memcpy(Far16ToFlat(ssb->f16SenseData), psd, ssb->ReqSenseLen);
[76]383 ssb->Flags |= STATUS_SENSEDATA_VALID;
[74]384 }
[178]385 pIorb->Status |= IORB_STATUSBLOCK_AVAIL;
[74]386 }
387
[60]388 /* map sense data to some IOERR_ value */
[178]389 switch (ATAPI_GET_SENSE(psd))
390 {
[60]391 case ASENSE_NO_SENSE:
392 case ASENSE_RECOVERED_ERROR:
[74]393 /* no error; this shouldn't happen because we'll only call
394 * atapi_req_sense() if we received an error interrupt */
[178]395 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
[60]396 break;
397
398 case ASENSE_NOT_READY:
[178]399 iorb_seterr(pIorb, IOERR_UNIT_NOT_READY);
[60]400 break;
401
402 case ASENSE_UNIT_ATTENTION:
[178]403 iorb_seterr(pIorb, IOERR_MEDIA_CHANGED);
[60]404 break;
405
406 case ASENSE_MEDIUM_ERROR:
[178]407 iorb_seterr(pIorb, IOERR_MEDIA);
[60]408 break;
409
410 case ASENSE_ILLEGAL_REQUEST:
[178]411 iorb_seterr(pIorb, IOERR_CMD_SYNTAX);
[60]412 break;
413
414 case ASENSE_DATA_PROTECT:
[178]415 iorb_seterr(pIorb, IOERR_MEDIA_WRITE_PROTECT);
[60]416 break;
417
418 case ASENSE_BLANK_CHECK:
[178]419 iorb_seterr(pIorb, IOERR_MEDIA_NOT_FORMATTED);
[60]420 break;
421
422 case ASENSE_ABORTED_COMMAND:
423 case ASENSE_COPY_ABORTED:
[178]424 iorb_seterr(pIorb, IOERR_CMD_ABORTED);
[60]425 break;
[87]426
[60]427 default:
[178]428 iorb_seterr(pIorb, IOERR_DEVICE_NONSPECIFIC);
[60]429 break;
430 }
431
[66]432 /* mark IORB as complete */
433 aws->complete = 1;
[60]434}
[65]435
[68]436/******************************************************************************
[76]437 * Pad ATAPI commands; AHCI requires ATAPI commands to be either 12 or
[68]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 */
[178]443int atapi_pad_cdb(u8 *cmd_in, u16 cmd_in_len, u8 *cmd_out, u16 *cmd_out_len)
[68]444{
[178]445 ATAPI_CDB_12 *p12;
[76]446 u32 tmp;
[68]447
[178]448 if (cmd_in_len == ATAPI_MIN_CDB_LEN || cmd_in_len == ATAPI_MAX_CDB_LEN)
449 {
[68]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);
[178]457 p12 = (ATAPI_CDB_12 *) cmd_out;
[68]458 /* we always convert to 12 byte CDBs */
459 *cmd_out_len = ATAPI_MIN_CDB_LEN;
460
461 /* check if command can be converted */
[178]462 switch (cmd_in[0])
463 {
[68]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.) */
[76]469 tmp = GET_CDB_24(cmd_in + 1) & 0x1fffffUL;
470 SET_CDB_32(p12->lba, tmp);
[178]471 SET_CDB_32(p12->trans_len, (cmd_in[4]));
[68]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];
[76]480 p12->control = cmd_in[9];
[68]481 memcpy(p12->lba, cmd_in + 2, 4);
[76]482 tmp = GET_CDB_16(cmd_in + 7);
483 SET_CDB_32(p12->trans_len, tmp);
[68]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.