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

Last change on this file since 65 was 65, checked in by root, 15 years ago

added padding to ATAPI CDBs

File size: 9.0 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 /* TODO: do we have to clear DMA_TO_HOST bit for
169 * write, mode select etc. commands?
170 */
171 AP_FEATURES, ATAPI_FEAT_DMA | ATAPI_FEAT_DMA_TO_HOST,
172 AP_END);
173
174 if (rc) {
175 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
176 }
177
178 return(rc);
179}
180
181
182/******************************************************************************
183 * Request sense information for a failed command.
184 *
185 * NOTE: This function must be called right after an ATAPI command has failed
186 * and before any other commands are queued on the corresponding device.
187 * This function is typically called in the port restart context hook
188 * which is triggered by an AHCI error interrupt.
189 *
190 */
191int atapi_req_sense(IORBH _far *iorb, int slot)
192{
193 ADD_WORKSPACE _far *aws = add_workspace(iorb);
194 int rc;
195 u8 cdb[ATAPI_MIN_CDB_LEN];
196 ATAPI_CDB_6 *pcdb; = (ATAPI_CDB_6*) cdb;
197
198 /* allocate sense buffer in ADD workspace */
199 aws->buf = malloc(ATAPI_SENSE_LEN);
200 if (aws->buf == NULL) {
201 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE);
202 return(-1);
203 }
204 memset(aws->buf, 0x00, ATAPI_SENSE_LEN);
205
206 /* prepare request sense command */
207 memset(cdb, 0x00, sizeof(cdb));
208 pcdb->cmd = ATAPI_CMD_REQUEST_SENSE;
209 pcdb->trans_len = (u8) ATAPI_SENSE_LEN;
210
211 aws->ppfunc = atapi_req_sense_pp;
212 rc = ata_cmd(ad_infos + iorb_unit_adapter(iorb),
213 iorb_unit_port(iorb),
214 iorb_unit_device(iorb),
215 slot,
216 ATA_CMD_PACKET,
217 AP_ATAPI_CMD, (void _far*) cdb, sizeof(cdb),
218 AP_VADDR, (void _far *) aws->buf, ATAPI_SENSE_LEN,
219 AP_FEATURES, ATAPI_FEAT_DMA,
220 AP_END);
221
222 if (rc > 0) {
223 iorb_seterr(iorb, IOERR_CMD_SGLIST_BAD);
224
225 } else {
226 /* we failed to get info about an error -> return
227 * non specific device error
228 */
229 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
230 }
231
232 return(rc);
233}
234
235/******************************************************************************
236 * Post processing function for ATAPI request sense; examines the sense
237 * data returned and maps sense info to IORB error info.
238 */
239static void atapi_req_sense_pp(IORBH _far *iorb)
240{
241 ADD_WORKSPACE _far *aws = add_workspace(iorb);
242 ATAPI_SENSE_DATA *psd = (ATAPI_SENSE_DATA *) aws->buf;
243
244 /* map sense data to some IOERR_ value */
245 switch (ATAPI_GET_SENSE(psd)) {
246
247 case ASENSE_NO_SENSE:
248 case ASENSE_RECOVERED_ERROR:
249 /* no error */
250 break;
251
252 case ASENSE_NOT_READY:
253 iorb_seterr(iorb, IOERR_UNIT_NOT_READY);
254 break;
255
256 case ASENSE_UNIT_ATTENTION:
257 iorb_seterr(iorb, IOERR_MEDIA_CHANGED);
258 break;
259
260 case ASENSE_MEDIUM_ERROR:
261 iorb_seterr(iorb, IOERR_MEDIA);
262 break;
263
264 case ASENSE_ILLEGAL_REQUEST:
265 iorb_seterr(iorb, IOERR_CMD_SYNTAX);
266 break;
267
268 case ASENSE_DATA_PROTECT:
269 iorb_seterr(iorb, IOERR_MEDIA_WRITE_PROTECT);
270 break;
271
272 case ASENSE_BLANK_CHECK:
273 iorb_seterr(iorb, IOERR_MEDIA_NOT_FORMATTED);
274 break;
275
276 case ASENSE_ABORTED_COMMAND:
277 case ASENSE_COPY_ABORTED:
278 iorb_seterr(iorb, IOERR_CMD_ABORTED);
279 break;
280
281 default:
282 iorb_seterr(iorb, IOERR_DEVICE_NONSPECIFIC);
283 break;
284 }
285
286 /* free sense buffer */
287 aws_free(aws);
288
289}
290
Note: See TracBrowser for help on using the repository browser.