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

Last change on this file since 87 was 87, checked in by markus, 14 years ago

changed copyright headers according to contract; removed evaluation message

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