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

Last change on this file since 76 was 76, checked in by chris, 15 years ago
  • APM support
  • Generic IOCTL interface for adapter passthrough commands (ATA and ATAPI)
  • Fixes to ATAPI sense data handling
  • Cosmetic changes to debug reporting
  • Fixed missing interrupt enable flag for PIO transfer completions
  • Added command line switch /I to ignore specific adapters
File size: 12.7 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, 0x4000,
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
204 if ((iorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
205 iorb->StatusBlockLen >= sizeof(*ssb) && iorb->pStatusBlock != 0) {
206
207 /* don't request sense data if caller asked us not to; the flag
208 * STATUS_DISABLE_REQEST_SENSE is not defined in the old DDK we've been
209 * using so we'll use the hard-coded value (0x0008) */
210 ssb = (SCSI_STATUS_BLOCK _far *) (((u32) iorb & 0xffff0000U) +
211 (u16) iorb->pStatusBlock);
212 if (ssb->Flags & 0x0008U) {
213 /* set a generic error code and skip automatic sense code handling */
214 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
215 return(-1);
216 }
217 }
218
219 /* allocate sense buffer in ADD workspace */
220 if ((aws->buf = malloc(ATAPI_SENSE_LEN)) == NULL) {
221 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
222 return(-1);
223 }
224 memset(aws->buf, 0x00, ATAPI_SENSE_LEN);
225
226 /* prepare request sense command */
227 memset(cdb, 0x00, sizeof(cdb));
228 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
229 pcdb->trans_len = (u8) ATAPI_SENSE_LEN;
230
231 aws->ppfunc = atapi_req_sense_pp;
232 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
233 iorb_unit_port(iorb),
234 iorb_unit_device(iorb),
235 slot,
236 ATA_CMD_PACKET,
237 AP_ATAPI_CMD, (void _far*) cdb, sizeof(cdb),
238 AP_VADDR, (void _far *) aws->buf, ATAPI_SENSE_LEN,
239 AP_FEATURES, ATAPI_FEAT_DMA,
240 AP_END);
241
242 if (rc > 0) {
243 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
244
245 } else if (rc < 0) {
246 /* we failed to get info about an error -> return
247 * non specific device error
248 */
249 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
250 }
251
252 return(rc);
253}
254
255/******************************************************************************
256 * Post processing function for ATAPI request sense; examines the sense
257 * data returned and maps sense info to IORB error info.
258 */
259static void atapi_req_sense_pp(IORBH _far *iorb)
260{
261 SCSI_STATUS_BLOCK _far *ssb;
262 ADD_WORKSPACE _far *aws = add_workspace(iorb);
263 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
264
265 dphex(psd, sizeof(*psd), "sense buffer:\n");
266
267 if ((iorb->RequestControl & IORB_REQ_STATUSBLOCK) &&
268 iorb->StatusBlockLen >= sizeof(*ssb) && iorb->pStatusBlock != 0) {
269
270 /* copy sense data to IORB */
271 ssb = (SCSI_STATUS_BLOCK _far *) (((u32) iorb & 0xffff0000U) +
272 (u16) iorb->pStatusBlock);
273 ssb->AdapterErrorCode = 0;
274 ssb->TargetStatus = SCSI_STAT_CHECKCOND;
275 ssb->ResidualLength = 0;
276 memset(ssb->AdapterDiagInfo, 0x00, sizeof(ssb->AdapterDiagInfo));
277
278 if (ssb->SenseData != NULL) {
279 memcpy(ssb->SenseData, psd, max(ssb->ReqSenseLen, ATAPI_SENSE_LEN));
280 ssb->Flags |= STATUS_SENSEDATA_VALID;
281 }
282 iorb->Status |= IORB_STATUSBLOCK_AVAIL;
283 }
284
285 /* map sense data to some IOERR_ value */
286 switch (ATAPI_GET_SENSE(psd)) {
287
288 case ASENSE_NO_SENSE:
289 case ASENSE_RECOVERED_ERROR:
290 /* no error; this shouldn't happen because we'll only call
291 * atapi_req_sense() if we received an error interrupt */
292 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
293 break;
294
295 case ASENSE_NOT_READY:
296 iorb_seterr(iorb, IOERR_UNIT_NOT_READY);
297 break;
298
299 case ASENSE_UNIT_ATTENTION:
300 iorb_seterr(iorb, IOERR_MEDIA_CHANGED);
301 break;
302
303 case ASENSE_MEDIUM_ERROR:
304 iorb_seterr(iorb, IOERR_MEDIA);
305 break;
306
307 case ASENSE_ILLEGAL_REQUEST:
308 iorb_seterr(iorb, IOERR_CMD_SYNTAX);
309 break;
310
311 case ASENSE_DATA_PROTECT:
312 iorb_seterr(iorb, IOERR_MEDIA_WRITE_PROTECT);
313 break;
314
315 case ASENSE_BLANK_CHECK:
316 iorb_seterr(iorb, IOERR_MEDIA_NOT_FORMATTED);
317 break;
318
319 case ASENSE_ABORTED_COMMAND:
320 case ASENSE_COPY_ABORTED:
321 iorb_seterr(iorb, IOERR_CMD_ABORTED);
322 break;
323
324 default:
325 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
326 break;
327 }
328
329 /* mark IORB as complete */
330 aws->complete = 1;
331}
332
333/******************************************************************************
334 * Pad ATAPI commands; AHCI requires ATAPI commands to be either 12 or
335 * 16 bytes in length. This func converts commands that have a 12 byte
336 * equivalent, and pads the others to 12 bytes.
337 * cmd_out buffer is expected to be ATAPI_MAX_CDB_LEN in size.
338 * returns 0 on success, != 0 if the command can't be converted.
339 */
340int atapi_pad_cdb(u8 _far *cmd_in, u16 cmd_in_len,
341 u8 _far *cmd_out, u16 _far *cmd_out_len)
342{
343 ATAPI_CDB_12 _far *p12;
344 u32 tmp;
345
346 if (cmd_in_len == ATAPI_MIN_CDB_LEN || cmd_in_len == ATAPI_MAX_CDB_LEN) {
347 /* command does not need to be converted */
348 memcpy(cmd_out, cmd_in, cmd_in_len);
349 *cmd_out_len = cmd_in_len;
350 return 0;
351 }
352
353 memset(cmd_out, 0x00, ATAPI_MAX_CDB_LEN);
354 p12 = (ATAPI_CDB_12 _far *) cmd_out;
355 /* we always convert to 12 byte CDBs */
356 *cmd_out_len = ATAPI_MIN_CDB_LEN;
357
358 /* check if command can be converted */
359 switch (cmd_in[0]) {
360
361 case ATAPI_CMD_READ_6:
362 case ATAPI_CMD_WRITE_6:
363 /* convert from 6 to 12 byte equivalent */
364 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
365 p12->flags = cmd_in[1] & 0xc0; /* 6byte cmds have no flags (FUA etc.) */
366 tmp = GET_CDB_24(cmd_in + 1) & 0x1fffffUL;
367 SET_CDB_32(p12->lba, tmp);
368 SET_CDB_32(p12->trans_len, cmd_in[4]);
369 p12->control = cmd_in[5];
370 break;
371
372 case ATAPI_CMD_READ_10:
373 case ATAPI_CMD_WRITE_10:
374 /* convert from 10 byte to 12 byte equivalent */
375 p12->cmd = 0xa0 | (cmd_in[0] & 0x0f);
376 p12->flags = cmd_in[1];
377 p12->control = cmd_in[9];
378 memcpy(p12->lba, cmd_in + 2, 4);
379 tmp = GET_CDB_16(cmd_in + 7);
380 SET_CDB_32(p12->trans_len, tmp);
381 break;
382
383 default:
384 /* pad with zeroes to 12 bytes */
385 memset(cmd_out, 0x00, ATAPI_MIN_CDB_LEN);
386 memcpy(cmd_out, cmd_in, cmd_in_len);
387 break;
388 }
389
390 return 0;
391}
392
Note: See TracBrowser for help on using the repository browser.