[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] | 35 | static void atapi_req_sense_pp(IORBH FAR16DATA *vIorb, IORBH *pIorb);
|
---|
| 36 | static 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] | 41 | int 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] | 51 | int 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] | 61 | int 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] | 148 | int 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] | 207 | int 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] | 217 | int 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] | 227 | int 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] | 280 | int 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] | 359 | static 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] | 443 | int 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 |
|
---|