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

Last change on this file since 67 was 67, checked in by markus, 15 years ago

set AP_WRITE flag for atapi_exec_cdb commands according to flags in IORB

File size: 9.1 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/* -------------------------- macros and constants ------------------------- */
28
29/* ------------------------ typedefs and structures ------------------------ */
30
31/* -------------------------- function prototypes -------------------------- */
32
33static void atapi_req_sense_pp (IORBH _far *iorb);
34
35/* ------------------------ global/static variables ------------------------ */
36
37/* ----------------------------- start of code ----------------------------- */
38
39/******************************************************************************
40 * Get device or media geometry. This function is not expected to be called.
41 */
42int atapi_get_geometry(IORBH _far *iorb, int slot)
43{
44 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
45 return(-1);
46}
47
48/******************************************************************************
49 * Test whether unit is ready. This function is not expected to be called.
50 */
51int atapi_unit_ready(IORBH _far *iorb, int slot)
52{
53 dprintf("atapi_unit_ready called\n");
54 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
55 return(-1);
56}
57
58/******************************************************************************
59 * Read sectors from AHCI device.
60 */
61int atapi_read(IORBH _far *iorb, int slot)
62{
63 IORB_EXECUTEIO _far *io = (IORB_EXECUTEIO _far *) iorb;
64 ATAPI_CDB_12 cdb;
65 AD_INFO *ai = ad_infos + iorb_unit_adapter(iorb);
66 USHORT count = io->BlockCount - io->BlocksXferred;
67 USHORT sg_indx;
68 USHORT sg_cnt;
69 int p = iorb_unit_port(iorb);
70 int d = iorb_unit_device(iorb);
71 int rc;
72
73 /* translate read command to SCSI/ATAPI READ12 command.
74 * READ12 seems to be the most supported READ variant - according to MMC,
75 * and its enough even for BluRay.
76 */
77 memset(&cdb, 0x00, sizeof(cdb));
78 cdb.cmd = ATAPI_CMD_READ_12;
79 SET_CDB_32(cdb.lba, io->RBA + io->BlocksXferred);
80
81 do {
82 /* update sector count (might have been updated due to S/G limitations) */
83 SET_CDB_32(cdb.trans_len, (u32) count);
84
85 /* update S/G count and index */
86 sg_indx = ata_get_sg_indx(io);
87 sg_cnt = io->cSGList - sg_indx;
88
89 /* issue command */
90 rc = ata_cmd(ai, p, d, slot, ATA_CMD_PACKET,
91 AP_ATAPI_CMD, (void _far *) &cdb, sizeof(cdb),
92 AP_SGLIST, io->pSGList + sg_indx, (u16) sg_cnt,
93 AP_DEVICE, 0x4000,
94 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
95 AP_END);
96
97 if (rc > 0) {
98 /* couldn't map all S/G elements */
99 ata_max_sg_cnt(io, sg_indx, (USHORT) rc, &sg_cnt, &count);
100 }
101 } while (rc > 0 && sg_cnt > 0);
102
103 if (rc == 0) {
104 add_workspace(iorb)->blocks = count;
105 add_workspace(iorb)->ppfunc = ata_read_pp;
106
107 } else if (rc > 0) {
108 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
109
110 } else {
111 iorb_seterr(iorb, IOERR_CMD_ADD_SOFTWARE_FAILURE);
112 }
113
114 return(rc);
115}
116
117/******************************************************************************
118 * Verify readability of sectors on AHCI device. This function is not expected
119 * to be called.
120 */
121int atapi_verify(IORBH _far *iorb, int slot)
122{
123 dprintf("atapi_verify called\n");
124 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
125 return(-1);
126}
127
128/******************************************************************************
129 * Write sectors to AHCI device. This function is not expected to be called.
130 */
131int atapi_write(IORBH _far *iorb, int slot)
132{
133 dprintf("atapi_write called\n");
134 iorb_seterr(iorb, IOERR_CMD_NOT_SUPPORTED);
135 return(-1);
136}
137
138/******************************************************************************
139 * Execute ATAPI command.
140 */
141int atapi_execute_cdb(IORBH _far *iorb, int slot)
142{
143 IORB_ADAPTER_PASSTHRU _far *pt = (IORB_ADAPTER_PASSTHRU _far *) iorb;
144 int rc;
145 u8 cdb[ATAPI_MAX_CDB_LEN] = {0};
146 u16 cdb_len;
147
148 if (pt->ControllerCmdLen > ATAPI_MAX_CDB_LEN) {
149 ioerb_seterr(IOERR_CMD_SYNTAX);
150 return -1;
151 }
152 /* AHCI requires 12 or 16 byte commands; for now, we pad them
153 * since I have no idea what to do with commands that do not
154 * have a 12 or 16 byte equivalent */
155 memcpy(cdb, pt->pControllerCmd, pt->ControllerCmdLen);
156 cdb_len = max(ATAPI_MIN_CDB_LEN, pt->ControllerCmdLen);
157
158 /* we do not perform the S/G limitation recovery loop here:
159 * "ADDs are not required to iterate commands through the CDB PassThru
160 * mechanism:" -- Storage Device Driver Reference, Scatter/Gather Lists
161 */
162 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
163 iorb_unit_port(iorb),
164 iorb_unit_device(iorb),
165 slot, ATA_CMD_PACKET,
166 AP_ATAPI_CMD, (void _far *) cdb, cdb_len,
167 AP_SGLIST, pt->pSGList, pt->cSGList,
168 AP_WRITE, !(pt->Flags & PT_DIRECTION_IN),
169 /* TODO: do we have to clear DMA_TO_HOST bit for
170 * write, mode select etc. commands?
171 */
172 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
173 AP_END);
174
175 if (rc) {
176 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
177 }
178
179 return(rc);
180}
181
182
183/******************************************************************************
184 * Request sense information for a failed command.
185 *
186 * NOTE: This function must be called right after an ATAPI command has failed
187 * and before any other commands are queued on the corresponding device.
188 * This function is typically called in the port restart context hook
189 * which is triggered by an AHCI error interrupt.
190 *
191 */
192int atapi_req_sense(IORBH _far *iorb, int slot)
193{
194 ADD_WORKSPACE _far *aws = add_workspace(iorb);
195 int rc;
196 u8 cdb[ATAPI_MIN_CDB_LEN];
197 ATAPI_CDB_6 *pcdb; = (ATAPI_CDB_6*) cdb;
198
199 /* allocate sense buffer in ADD workspace */
200 aws->buf = malloc(ATAPI_SENSE_LEN);
201 if (aws->buf == NULL) {
202 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
203 return(-1);
204 }
205 memset(aws->buf, 0x00, ATAPI_SENSE_LEN);
206
207 /* prepare request sense command */
208 memset(cdb, 0x00, sizeof(cdb));
209 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
210 pcdb->trans_len = (u8) ATAPI_SENSE_LEN;
211
212 aws->ppfunc = atapi_req_sense_pp;
213 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
214 iorb_unit_port(iorb),
215 iorb_unit_device(iorb),
216 slot,
217 ATA_CMD_PACKET,
218 AP_ATAPI_CMD, (void _far*) cdb, sizeof(cdb),
219 AP_VADDR, (void _far *) aws->buf, ATAPI_SENSE_LEN,
220 AP_FEATURES, ATAPI_FEAT_DMA,
221 AP_END);
222
223 if (rc > 0) {
224 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
225
226 } else {
227 /* we failed to get info about an error -> return
228 * non specific device error
229 */
230 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
231 }
232
233 return(rc);
234}
235
236/******************************************************************************
237 * Post processing function for ATAPI request sense; examines the sense
238 * data returned and maps sense info to IORB error info.
239 */
240static void atapi_req_sense_pp(IORBH _far *iorb)
241{
242 ADD_WORKSPACE _far *aws = add_workspace(iorb);
243 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
244
245 /* map sense data to some IOERR_ value */
246 switch (ATAPI_GET_SENSE(psd)) {
247
248 case ASENSE_NO_SENSE:
249 case ASENSE_RECOVERED_ERROR:
250 /* no error */
251 break;
252
253 case ASENSE_NOT_READY:
254 iorb_seterr(iorb, IOERR_UNIT_NOT_READY);
255 break;
256
257 case ASENSE_UNIT_ATTENTION:
258 iorb_seterr(iorb, IOERR_MEDIA_CHANGED);
259 break;
260
261 case ASENSE_MEDIUM_ERROR:
262 iorb_seterr(iorb, IOERR_MEDIA);
263 break;
264
265 case ASENSE_ILLEGAL_REQUEST:
266 iorb_seterr(iorb, IOERR_CMD_SYNTAX);
267 break;
268
269 case ASENSE_DATA_PROTECT:
270 iorb_seterr(iorb, IOERR_MEDIA_WRITE_PROTECT);
271 break;
272
273 case ASENSE_BLANK_CHECK:
274 iorb_seterr(iorb, IOERR_MEDIA_NOT_FORMATTED);
275 break;
276
277 case ASENSE_ABORTED_COMMAND:
278 case ASENSE_COPY_ABORTED:
279 iorb_seterr(iorb, IOERR_CMD_ABORTED);
280 break;
281
282 default:
283 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
284 break;
285 }
286
287 /* mark IORB as complete */
288 aws->complete = 1;
289}
290
Note: See TracBrowser for help on using the repository browser.