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

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

added atapi_ calls; untested

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