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

Last change on this file since 82 was 82, checked in by chris, 14 years ago

Version 1.09
============

  • Added new command line parameter, "/4", which will force a track size of 56 sectors to be reported in geometry requests. This will improve performance for newer HDs with 4K sectors and file systems which use block sizes larger than 512 bytes (FAT, JFS, ...) because all partitions will be aligned on 4K (8 sector) boundaries.
  • Changed AP_DEVICE parameter to ata_cmd() from 16 bits to 8 bits -- the corresponding field in ATA_CMD has always been 8 bits and there's no point discarding the lower 8 bits of the AP_DEVICE parameter as a general rule. Besides, it confused me in the end...
  • Always return some kind of error in ata_req_sense() because this function will only be called when we received an error interrupt; atapi_req_sense() already does this.
  • Cosmetic changes
File size: 12.9 KB
Line 
1/******************************************************************************
2 * atapi.c - ATAPI command processing
3 *
4 * Copyright (c) 2010 Christian Mueller, Markus Thielen.
5 * Parts copied from/inspired by the Linux AHCI driver;
6 * those parts are (c) Linux AHCI/ATA maintainers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "os2ahci.h"
24#include "ata.h"
25#include "atapi.h"
26
27/* need this for the SCSI status block */
28#include <scsi.h>
29
30/* -------------------------- macros and constants ------------------------- */
31
32/* ------------------------ typedefs and structures ------------------------ */
33
34/* -------------------------- function prototypes -------------------------- */
35
36static void atapi_req_sense_pp (IORBH _far *iorb);
37static int atapi_pad_cdb (u8 _far *cmd_in, u16 cmd_in_len,
38 u8 _far *cmd_out, u16 _far *cmd_out_len);
39
40/* ------------------------ global/static variables ------------------------ */
41
42/* ----------------------------- start of code ----------------------------- */
43
44/******************************************************************************
45 * Get device or media geometry. This function is not expected to be called.
46 */
47int atapi_get_geometry(IORBH _far *iorb, int slot)
48{
49 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
50 return(-1);
51}
52
53/******************************************************************************
54 * Test whether unit is ready. This function is not expected to be called.
55 */
56int atapi_unit_ready(IORBH _far *iorb, int slot)
57{
58 ddprintf("atapi_unit_ready called\n");
59 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
60 return(-1);
61}
62
63/******************************************************************************
64 * Read sectors from AHCI device.
65 */
66int atapi_read(IORBH _far *iorb, int slot)
67{
68 IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
69 ATAPI_CDB_12 cdb;
70 AD_INFO *ai = ad_infos + iorb_unit_adapter(iorb);
71 USHORT count = io->BlockCount - io->BlocksXferred;
72 USHORT sg_indx;
73 USHORT sg_cnt;
74 int p = iorb_unit_port(iorb);
75 int d = iorb_unit_device(iorb);
76 int rc;
77
78 /* translate read command to SCSI/ATAPI READ12 command.
79 * READ12 seems to be the most supported READ variant - according to MMC,
80 * and it's enough even for BluRay.
81 */
82 memset(&cdb, 0x00, sizeof(cdb));
83 cdb.cmd = ATAPI_CMD_READ_12;
84 SET_CDB_32(cdb.lba, io->RBA + io->BlocksXferred);
85
86 do {
87 /* update sector count (might have been updated due to S/G limitations) */
88 SET_CDB_32(cdb.trans_len, (u32) count);
89
90 /* update S/G count and index */
91 sg_indx = ata_get_sg_indx(io);
92 sg_cnt = io->cSGList - sg_indx;
93
94 /* issue command */
95 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
96 AP_ATAPI_CMD, (void _far *) &cdb, sizeof(cdb),
97 AP_SGLIST, io->pSGList + sg_indx, (u16) sg_cnt,
98 AP_DEVICE, 0x40,
99 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
100 AP_END);
101
102 if (rc > 0) {
103 /* couldn't map all S/G elements */
104 ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
105 }
106 } while (rc > 0 && sg_cnt > 0);
107
108 if (rc == 0) {
109 add_workspace(iorb)->blocks = count;
110 add_workspace(iorb)->ppfunc = ata_read_pp;
111
112 } else if (rc > 0) {
113 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
114
115 } else {
116 iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
117 }
118
119 return(rc);
120}
121
122/******************************************************************************
123 * Verify readability of sectors on AHCI device. This function is not expected
124 * to be called.
125 */
126int atapi_verify(IORBH _far *iorb, int slot)
127{
128 ddprintf("atapi_verify called\n");
129 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
130 return(-1);
131}
132
133/******************************************************************************
134 * Write sectors to AHCI device. This function is not expected to be called.
135 */
136int atapi_write(IORBH _far *iorb, int slot)
137{
138 ddprintf("atapi_write called\n");
139 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
140 return(-1);
141}
142
143/******************************************************************************
144 * Execute ATAPI command.
145 */
146int atapi_execute_cdb(IORBH _far *iorb, int slot)
147{
148 IORB_ADAPTER_PASSTHRU _far *pt = (IORB_ADAPTER_PASSTHRU _far *) iorb;
149 int rc;
150 u8 cdb[ATAPI_MAX_CDB_LEN];
151 u16 cdb_len;
152
153 if (pt->ControllerCmdLen > ATAPI_MAX_CDB_LEN) {
154 iorb_seterr(iorb, IOERR_CMD_SYNTAX);
155 return -1;
156 }
157 /* AHCI requires 12 or 16 byte commands */
158 atapi_pad_cdb(pt->pControllerCmd, pt->ControllerCmdLen,
159 (u8 _far *) cdb, (u16 _far *) &cdb_len);
160
161 if (cdb[0] == 0x12 || cdb[0] == 0x5a) {
162 /* somebody sets the direction flag incorrectly for those commands */
163 pt->Flags |= PT_DIRECTION_IN;
164 }
165
166 /* we do not perform the S/G limitation recovery loop here:
167 * "ADDs are not required to iterate commands through the CDB PassThru
168 * mechanism:" -- Storage Device Driver Reference, Scatter/Gather Lists
169 */
170 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb), iorb_unit_port(iorb),
171 iorb_unit_device(iorb), slot, ATA_CMD_PACKET,
172 AP_ATAPI_CMD, (void _far *) cdb, cdb_len,
173 AP_SGLIST, pt->pSGList, pt->cSGList,
174 AP_WRITE, !(pt->Flags & PT_DIRECTION_IN),
175 AP_FEATURES, ATAPI_FEAT_DMA,
176 AP_FEATURES, (pt->Flags & PT_DIRECTION_IN) ? ATAPI_FEAT_DMA_TO_HOST : 0,
177 AP_END);
178
179 if (rc) {
180 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
181 }
182
183 return(rc);
184}
185
186
187/******************************************************************************
188 * Request sense information for a failed command.
189 *
190 * NOTE: This function must be called right after an ATAPI command has failed
191 * and before any other commands are queued on the corresponding device.
192 * This function is typically called in the port restart context hook
193 * which is triggered by an AHCI error interrupt.
194 *
195 */
196int atapi_req_sense(IORBH _far *iorb, int slot)
197{
198 SCSI_STATUS_BLOCK _far *ssb;
199 ADD_WORKSPACE _far *aws = add_workspace(iorb);
200 int rc;
201 u8 cdb[ATAPI_MIN_CDB_LEN];
202 ATAPI_CDB_6 _far *pcdb = (ATAPI_CDB_6 _far *) cdb;
203 size_t sense_buf_len = ATAPI_SENSE_LEN;
204
205 if ((iorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
206 iorb->StatusBlockLen >= sizeof(*ssb) && iorb->pStatusBlock != 0) {
207
208 /* don't request sense data if caller asked us not to; the flag
209 * STATUS_DISABLE_REQEST_SENSE is not defined in the old DDK we've been
210 * using so we'll use the hard-coded value (0x0008) */
211 ssb = (SCSI_STATUS_BLOCK _far *) (((u32) iorb & 0xffff0000U) +
212 (u16) iorb->pStatusBlock);
213 if (ssb->Flags & 0x0008U) {
214 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
215 return(-1);
216 }
217
218 /* if the sense buffer requested is larger than our default, adjust
219 * the length accordingly to satisfy the caller's requirements. */
220 if (ssb->SenseData != NULL && ssb->ReqSenseLen > sense_buf_len) {
221 sense_buf_len = ssb->ReqSenseLen;
222 }
223 }
224
225 /* allocate sense buffer in ADD workspace */
226 if ((aws->buf = malloc(sense_buf_len)) == NULL) {
227 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
228 return(-1);
229 }
230 memset(aws->buf, 0x00, sense_buf_len);
231
232 /* prepare request sense command */
233 memset(cdb, 0x00, sizeof(cdb));
234 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
235 pcdb->trans_len = (u8) sense_buf_len;
236
237 aws->ppfunc = atapi_req_sense_pp;
238 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
239 iorb_unit_port(iorb),
240 iorb_unit_device(iorb),
241 slot,
242 ATA_CMD_PACKET,
243 AP_ATAPI_CMD, (void _far*) cdb, sizeof(cdb),
244 AP_VADDR, (void _far *) aws->buf, sense_buf_len,
245 AP_FEATURES, ATAPI_FEAT_DMA,
246 AP_END);
247
248 if (rc > 0) {
249 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
250
251 } else if (rc < 0) {
252 /* we failed to get info about an error -> return
253 * non specific device error
254 */
255 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
256 }
257
258 return(rc);
259}
260
261/******************************************************************************
262 * Post processing function for ATAPI request sense; examines the sense
263 * data returned and maps sense info to IORB error info.
264 */
265static void atapi_req_sense_pp(IORBH _far *iorb)
266{
267 SCSI_STATUS_BLOCK _far *ssb;
268 ADD_WORKSPACE _far *aws = add_workspace(iorb);
269 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
270
271 dphex(psd, sizeof(*psd), "sense buffer:\n");
272
273 if ((iorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
274 iorb->StatusBlockLen >= sizeof(*ssb) && iorb->pStatusBlock != 0) {
275
276 /* copy sense data to IORB */
277 ssb = (SCSI_STATUS_BLOCK _far *) (((u32) iorb & 0xffff0000U) +
278 (u16) iorb->pStatusBlock);
279 ssb->AdapterErrorCode = 0;
280 ssb->TargetStatus = SCSI_STAT_CHECKCOND;
281 ssb->ResidualLength = 0;
282 memset(ssb->AdapterDiagInfo, 0x00, sizeof(ssb->AdapterDiagInfo));
283
284 if (ssb->SenseData != NULL) {
285 memcpy(ssb->SenseData, psd, ssb->ReqSenseLen);
286 ssb->Flags |= STATUS_SENSEDATA_VALID;
287 }
288 iorb->Status |= IORB_STATUSBLOCK_AVAIL;
289 }
290
291 /* map sense data to some IOERR_ value */
292 switch (ATAPI_GET_SENSE(psd)) {
293
294 case ASENSE_NO_SENSE:
295 case ASENSE_RECOVERED_ERROR:
296 /* no error; this shouldn't happen because we'll only call
297 * atapi_req_sense() if we received an error interrupt */
298 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
299 break;
300
301 case ASENSE_NOT_READY:
302 iorb_seterr(iorb, IOERR_UNIT_NOT_READY);
303 break;
304
305 case ASENSE_UNIT_ATTENTION:
306 iorb_seterr(iorb, IOERR_MEDIA_CHANGED);
307 break;
308
309 case ASENSE_MEDIUM_ERROR:
310 iorb_seterr(iorb, IOERR_MEDIA);
311 break;
312
313 case ASENSE_ILLEGAL_REQUEST:
314 iorb_seterr(iorb, IOERR_CMD_SYNTAX);
315 break;
316
317 case ASENSE_DATA_PROTECT:
318 iorb_seterr(iorb, IOERR_MEDIA_WRITE_PROTECT);
319 break;
320
321 case ASENSE_BLANK_CHECK:
322 iorb_seterr(iorb, IOERR_MEDIA_NOT_FORMATTED);
323 break;
324
325 case ASENSE_ABORTED_COMMAND:
326 case ASENSE_COPY_ABORTED:
327 iorb_seterr(iorb, IOERR_CMD_ABORTED);
328 break;
329
330 default:
331 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
332 break;
333 }
334
335 /* mark IORB as complete */
336 aws->complete = 1;
337}
338
339/******************************************************************************
340 * Pad ATAPI commands; AHCI requires ATAPI commands to be either 12 or
341 * 16 bytes in length. This func converts commands that have a 12 byte
342 * equivalent, and pads the others to 12 bytes.
343 * cmd_out buffer is expected to be ATAPI_MAX_CDB_LEN in size.
344 * returns 0 on success, != 0 if the command can't be converted.
345 */
346int atapi_pad_cdb(u8 _far *cmd_in, u16 cmd_in_len,
347 u8 _far *cmd_out, u16 _far *cmd_out_len)
348{
349 ATAPI_CDB_12 _far *p12;
350 u32 tmp;
351
352 if (cmd_in_len == ATAPI_MIN_CDB_LEN || cmd_in_len == ATAPI_MAX_CDB_LEN) {
353 /* command does not need to be converted */
354 memcpy(cmd_out, cmd_in, cmd_in_len);
355 *cmd_out_len = cmd_in_len;
356 return 0;
357 }
358
359 memset(cmd_out, 0x00, ATAPI_MAX_CDB_LEN);
360 p12 = (ATAPI_CDB_12 _far *) cmd_out;
361 /* we always convert to 12 byte CDBs */
362 *cmd_out_len = ATAPI_MIN_CDB_LEN;
363
364 /* check if command can be converted */
365 switch (cmd_in[0]) {
366
367 case ATAPI_CMD_READ_6:
368 case ATAPI_CMD_WRITE_6:
369 /* convert from 6 to 12 byte equivalent */
370 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
371 p12->flags = cmd_in[1] & 0xc0; /* 6byte cmds have no flags (FUA etc.) */
372 tmp = GET_CDB_24(cmd_in + 1) & 0x1fffffUL;
373 SET_CDB_32(p12->lba, tmp);
374 SET_CDB_32(p12->trans_len, cmd_in[4]);
375 p12->control = cmd_in[5];
376 break;
377
378 case ATAPI_CMD_READ_10:
379 case ATAPI_CMD_WRITE_10:
380 /* convert from 10 byte to 12 byte equivalent */
381 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
382 p12->flags = cmd_in[1];
383 p12->control = cmd_in[9];
384 memcpy(p12->lba, cmd_in + 2, 4);
385 tmp = GET_CDB_16(cmd_in + 7);
386 SET_CDB_32(p12->trans_len, tmp);
387 break;
388
389 default:
390 /* pad with zeroes to 12 bytes */
391 memset(cmd_out, 0x00, ATAPI_MIN_CDB_LEN);
392 memcpy(cmd_out, cmd_in, cmd_in_len);
393 break;
394 }
395
396 return 0;
397}
398
Note: See TracBrowser for help on using the repository browser.