diff options
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 183 |
1 files changed, 117 insertions, 66 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 7201b176d75b..757e5956b132 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c | |||
@@ -80,34 +80,6 @@ void ide_init_pc(struct ide_atapi_pc *pc) | |||
80 | EXPORT_SYMBOL_GPL(ide_init_pc); | 80 | EXPORT_SYMBOL_GPL(ide_init_pc); |
81 | 81 | ||
82 | /* | 82 | /* |
83 | * Generate a new packet command request in front of the request queue, before | ||
84 | * the current request, so that it will be processed immediately, on the next | ||
85 | * pass through the driver. | ||
86 | */ | ||
87 | static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | ||
88 | struct ide_atapi_pc *pc, struct request *rq) | ||
89 | { | ||
90 | blk_rq_init(NULL, rq); | ||
91 | rq->cmd_type = REQ_TYPE_SPECIAL; | ||
92 | rq->cmd_flags |= REQ_PREEMPT; | ||
93 | rq->buffer = (char *)pc; | ||
94 | rq->rq_disk = disk; | ||
95 | |||
96 | if (pc->req_xfer) { | ||
97 | rq->data = pc->buf; | ||
98 | rq->data_len = pc->req_xfer; | ||
99 | } | ||
100 | |||
101 | memcpy(rq->cmd, pc->c, 12); | ||
102 | if (drive->media == ide_tape) | ||
103 | rq->cmd[13] = REQ_IDETAPE_PC1; | ||
104 | |||
105 | drive->hwif->rq = NULL; | ||
106 | |||
107 | elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Add a special packet command request to the tail of the request queue, | 83 | * Add a special packet command request to the tail of the request queue, |
112 | * and wait for it to be serviced. | 84 | * and wait for it to be serviced. |
113 | */ | 85 | */ |
@@ -119,19 +91,21 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, | |||
119 | 91 | ||
120 | rq = blk_get_request(drive->queue, READ, __GFP_WAIT); | 92 | rq = blk_get_request(drive->queue, READ, __GFP_WAIT); |
121 | rq->cmd_type = REQ_TYPE_SPECIAL; | 93 | rq->cmd_type = REQ_TYPE_SPECIAL; |
122 | rq->buffer = (char *)pc; | 94 | rq->special = (char *)pc; |
123 | 95 | ||
124 | if (pc->req_xfer) { | 96 | if (pc->req_xfer) { |
125 | rq->data = pc->buf; | 97 | error = blk_rq_map_kern(drive->queue, rq, pc->buf, pc->req_xfer, |
126 | rq->data_len = pc->req_xfer; | 98 | GFP_NOIO); |
99 | if (error) | ||
100 | goto put_req; | ||
127 | } | 101 | } |
128 | 102 | ||
129 | memcpy(rq->cmd, pc->c, 12); | 103 | memcpy(rq->cmd, pc->c, 12); |
130 | if (drive->media == ide_tape) | 104 | if (drive->media == ide_tape) |
131 | rq->cmd[13] = REQ_IDETAPE_PC1; | 105 | rq->cmd[13] = REQ_IDETAPE_PC1; |
132 | error = blk_execute_rq(drive->queue, disk, rq, 0); | 106 | error = blk_execute_rq(drive->queue, disk, rq, 0); |
107 | put_req: | ||
133 | blk_put_request(rq); | 108 | blk_put_request(rq); |
134 | |||
135 | return error; | 109 | return error; |
136 | } | 110 | } |
137 | EXPORT_SYMBOL_GPL(ide_queue_pc_tail); | 111 | EXPORT_SYMBOL_GPL(ide_queue_pc_tail); |
@@ -191,20 +165,113 @@ void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) | |||
191 | } | 165 | } |
192 | EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); | 166 | EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); |
193 | 167 | ||
168 | void ide_prep_sense(ide_drive_t *drive, struct request *rq) | ||
169 | { | ||
170 | struct request_sense *sense = &drive->sense_data; | ||
171 | struct request *sense_rq = &drive->sense_rq; | ||
172 | unsigned int cmd_len, sense_len; | ||
173 | int err; | ||
174 | |||
175 | debug_log("%s: enter\n", __func__); | ||
176 | |||
177 | switch (drive->media) { | ||
178 | case ide_floppy: | ||
179 | cmd_len = 255; | ||
180 | sense_len = 18; | ||
181 | break; | ||
182 | case ide_tape: | ||
183 | cmd_len = 20; | ||
184 | sense_len = 20; | ||
185 | break; | ||
186 | default: | ||
187 | cmd_len = 18; | ||
188 | sense_len = 18; | ||
189 | } | ||
190 | |||
191 | BUG_ON(sense_len > sizeof(*sense)); | ||
192 | |||
193 | if (blk_sense_request(rq) || drive->sense_rq_armed) | ||
194 | return; | ||
195 | |||
196 | memset(sense, 0, sizeof(*sense)); | ||
197 | |||
198 | blk_rq_init(rq->q, sense_rq); | ||
199 | |||
200 | err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, | ||
201 | GFP_NOIO); | ||
202 | if (unlikely(err)) { | ||
203 | if (printk_ratelimit()) | ||
204 | printk(KERN_WARNING "%s: failed to map sense buffer\n", | ||
205 | drive->name); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | sense_rq->rq_disk = rq->rq_disk; | ||
210 | sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; | ||
211 | sense_rq->cmd[4] = cmd_len; | ||
212 | sense_rq->cmd_type = REQ_TYPE_SENSE; | ||
213 | sense_rq->cmd_flags |= REQ_PREEMPT; | ||
214 | |||
215 | if (drive->media == ide_tape) | ||
216 | sense_rq->cmd[13] = REQ_IDETAPE_PC1; | ||
217 | |||
218 | drive->sense_rq_armed = true; | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(ide_prep_sense); | ||
221 | |||
222 | int ide_queue_sense_rq(ide_drive_t *drive, void *special) | ||
223 | { | ||
224 | /* deferred failure from ide_prep_sense() */ | ||
225 | if (!drive->sense_rq_armed) { | ||
226 | printk(KERN_WARNING "%s: failed queue sense request\n", | ||
227 | drive->name); | ||
228 | return -ENOMEM; | ||
229 | } | ||
230 | |||
231 | drive->sense_rq.special = special; | ||
232 | drive->sense_rq_armed = false; | ||
233 | |||
234 | drive->hwif->rq = NULL; | ||
235 | |||
236 | elv_add_request(drive->queue, &drive->sense_rq, | ||
237 | ELEVATOR_INSERT_FRONT, 0); | ||
238 | return 0; | ||
239 | } | ||
240 | EXPORT_SYMBOL_GPL(ide_queue_sense_rq); | ||
241 | |||
194 | /* | 242 | /* |
195 | * Called when an error was detected during the last packet command. | 243 | * Called when an error was detected during the last packet command. |
196 | * We queue a request sense packet command in the head of the request list. | 244 | * We queue a request sense packet command at the head of the request |
245 | * queue. | ||
197 | */ | 246 | */ |
198 | void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk) | 247 | void ide_retry_pc(ide_drive_t *drive) |
199 | { | 248 | { |
200 | struct request *rq = &drive->request_sense_rq; | 249 | struct request *failed_rq = drive->hwif->rq; |
250 | struct request *sense_rq = &drive->sense_rq; | ||
201 | struct ide_atapi_pc *pc = &drive->request_sense_pc; | 251 | struct ide_atapi_pc *pc = &drive->request_sense_pc; |
202 | 252 | ||
203 | (void)ide_read_error(drive); | 253 | (void)ide_read_error(drive); |
204 | ide_create_request_sense_cmd(drive, pc); | 254 | |
255 | /* init pc from sense_rq */ | ||
256 | ide_init_pc(pc); | ||
257 | memcpy(pc->c, sense_rq->cmd, 12); | ||
258 | pc->buf = bio_data(sense_rq->bio); /* pointer to mapped address */ | ||
259 | pc->req_xfer = blk_rq_bytes(sense_rq); | ||
260 | |||
205 | if (drive->media == ide_tape) | 261 | if (drive->media == ide_tape) |
206 | set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); | 262 | set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); |
207 | ide_queue_pc_head(drive, disk, pc, rq); | 263 | |
264 | /* | ||
265 | * Push back the failed request and put request sense on top | ||
266 | * of it. The failed command will be retried after sense data | ||
267 | * is acquired. | ||
268 | */ | ||
269 | blk_requeue_request(failed_rq->q, failed_rq); | ||
270 | drive->hwif->rq = NULL; | ||
271 | if (ide_queue_sense_rq(drive, pc)) { | ||
272 | blk_start_request(failed_rq); | ||
273 | ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); | ||
274 | } | ||
208 | } | 275 | } |
209 | EXPORT_SYMBOL_GPL(ide_retry_pc); | 276 | EXPORT_SYMBOL_GPL(ide_retry_pc); |
210 | 277 | ||
@@ -246,7 +313,7 @@ int ide_cd_get_xferlen(struct request *rq) | |||
246 | return 32768; | 313 | return 32768; |
247 | else if (blk_sense_request(rq) || blk_pc_request(rq) || | 314 | else if (blk_sense_request(rq) || blk_pc_request(rq) || |
248 | rq->cmd_type == REQ_TYPE_ATA_PC) | 315 | rq->cmd_type == REQ_TYPE_ATA_PC) |
249 | return rq->data_len; | 316 | return blk_rq_bytes(rq); |
250 | else | 317 | else |
251 | return 0; | 318 | return 0; |
252 | } | 319 | } |
@@ -276,7 +343,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
276 | struct ide_cmd *cmd = &hwif->cmd; | 343 | struct ide_cmd *cmd = &hwif->cmd; |
277 | struct request *rq = hwif->rq; | 344 | struct request *rq = hwif->rq; |
278 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 345 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
279 | xfer_func_t *xferfunc; | ||
280 | unsigned int timeout, done; | 346 | unsigned int timeout, done; |
281 | u16 bcount; | 347 | u16 bcount; |
282 | u8 stat, ireason, dsc = 0; | 348 | u8 stat, ireason, dsc = 0; |
@@ -303,18 +369,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
303 | drive->name, rq_data_dir(pc->rq) | 369 | drive->name, rq_data_dir(pc->rq) |
304 | ? "write" : "read"); | 370 | ? "write" : "read"); |
305 | pc->flags |= PC_FLAG_DMA_ERROR; | 371 | pc->flags |= PC_FLAG_DMA_ERROR; |
306 | } else { | 372 | } else |
307 | pc->xferred = pc->req_xfer; | 373 | pc->xferred = pc->req_xfer; |
308 | if (drive->pc_update_buffers) | ||
309 | drive->pc_update_buffers(drive, pc); | ||
310 | } | ||
311 | debug_log("%s: DMA finished\n", drive->name); | 374 | debug_log("%s: DMA finished\n", drive->name); |
312 | } | 375 | } |
313 | 376 | ||
314 | /* No more interrupts */ | 377 | /* No more interrupts */ |
315 | if ((stat & ATA_DRQ) == 0) { | 378 | if ((stat & ATA_DRQ) == 0) { |
316 | int uptodate, error; | 379 | int uptodate, error; |
317 | unsigned int done; | ||
318 | 380 | ||
319 | debug_log("Packet command completed, %d bytes transferred\n", | 381 | debug_log("Packet command completed, %d bytes transferred\n", |
320 | pc->xferred); | 382 | pc->xferred); |
@@ -343,7 +405,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
343 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); | 405 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); |
344 | 406 | ||
345 | /* Retry operation */ | 407 | /* Retry operation */ |
346 | ide_retry_pc(drive, rq->rq_disk); | 408 | ide_retry_pc(drive); |
347 | 409 | ||
348 | /* queued, but not started */ | 410 | /* queued, but not started */ |
349 | return ide_stopped; | 411 | return ide_stopped; |
@@ -353,6 +415,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
353 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) | 415 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) |
354 | dsc = 1; | 416 | dsc = 1; |
355 | 417 | ||
418 | /* | ||
419 | * ->pc_callback() might change rq->data_len for | ||
420 | * residual count, cache total length. | ||
421 | */ | ||
422 | done = blk_rq_bytes(rq); | ||
423 | |||
356 | /* Command finished - Call the callback function */ | 424 | /* Command finished - Call the callback function */ |
357 | uptodate = drive->pc_callback(drive, dsc); | 425 | uptodate = drive->pc_callback(drive, dsc); |
358 | 426 | ||
@@ -361,7 +429,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
361 | 429 | ||
362 | if (blk_special_request(rq)) { | 430 | if (blk_special_request(rq)) { |
363 | rq->errors = 0; | 431 | rq->errors = 0; |
364 | done = blk_rq_bytes(rq); | ||
365 | error = 0; | 432 | error = 0; |
366 | } else { | 433 | } else { |
367 | 434 | ||
@@ -370,15 +437,10 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
370 | rq->errors = -EIO; | 437 | rq->errors = -EIO; |
371 | } | 438 | } |
372 | 439 | ||
373 | if (drive->media == ide_tape) | ||
374 | done = ide_rq_bytes(rq); /* FIXME */ | ||
375 | else | ||
376 | done = blk_rq_bytes(rq); | ||
377 | |||
378 | error = uptodate ? 0 : -EIO; | 440 | error = uptodate ? 0 : -EIO; |
379 | } | 441 | } |
380 | 442 | ||
381 | ide_complete_rq(drive, error, done); | 443 | ide_complete_rq(drive, error, blk_rq_bytes(rq)); |
382 | return ide_stopped; | 444 | return ide_stopped; |
383 | } | 445 | } |
384 | 446 | ||
@@ -407,21 +469,11 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
407 | return ide_do_reset(drive); | 469 | return ide_do_reset(drive); |
408 | } | 470 | } |
409 | 471 | ||
410 | xferfunc = write ? tp_ops->output_data : tp_ops->input_data; | 472 | done = min_t(unsigned int, bcount, cmd->nleft); |
411 | 473 | ide_pio_bytes(drive, cmd, write, done); | |
412 | if (drive->media == ide_floppy && pc->buf == NULL) { | ||
413 | done = min_t(unsigned int, bcount, cmd->nleft); | ||
414 | ide_pio_bytes(drive, cmd, write, done); | ||
415 | } else if (drive->media == ide_tape && pc->bh) { | ||
416 | done = drive->pc_io_buffers(drive, pc, bcount, write); | ||
417 | } else { | ||
418 | done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); | ||
419 | xferfunc(drive, NULL, pc->cur_pos, done); | ||
420 | } | ||
421 | 474 | ||
422 | /* Update the current position */ | 475 | /* Update transferred byte count */ |
423 | pc->xferred += done; | 476 | pc->xferred += done; |
424 | pc->cur_pos += done; | ||
425 | 477 | ||
426 | bcount -= done; | 478 | bcount -= done; |
427 | 479 | ||
@@ -599,7 +651,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) | |||
599 | 651 | ||
600 | /* We haven't transferred any data yet */ | 652 | /* We haven't transferred any data yet */ |
601 | pc->xferred = 0; | 653 | pc->xferred = 0; |
602 | pc->cur_pos = pc->buf; | ||
603 | 654 | ||
604 | valid_tf = IDE_VALID_DEVICE; | 655 | valid_tf = IDE_VALID_DEVICE; |
605 | bcount = ((drive->media == ide_tape) ? | 656 | bcount = ((drive->media == ide_tape) ? |