diff options
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 168 |
1 files changed, 105 insertions, 63 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 7201b176d75b..afe5a4323879 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,103 @@ 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 *sense_rq = &drive->sense_rq; |
201 | struct ide_atapi_pc *pc = &drive->request_sense_pc; | 250 | struct ide_atapi_pc *pc = &drive->request_sense_pc; |
202 | 251 | ||
203 | (void)ide_read_error(drive); | 252 | (void)ide_read_error(drive); |
204 | ide_create_request_sense_cmd(drive, pc); | 253 | |
254 | /* init pc from sense_rq */ | ||
255 | ide_init_pc(pc); | ||
256 | memcpy(pc->c, sense_rq->cmd, 12); | ||
257 | pc->buf = bio_data(sense_rq->bio); /* pointer to mapped address */ | ||
258 | pc->req_xfer = sense_rq->data_len; | ||
259 | |||
205 | if (drive->media == ide_tape) | 260 | if (drive->media == ide_tape) |
206 | set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); | 261 | set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); |
207 | ide_queue_pc_head(drive, disk, pc, rq); | 262 | |
263 | if (ide_queue_sense_rq(drive, pc)) | ||
264 | ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); | ||
208 | } | 265 | } |
209 | EXPORT_SYMBOL_GPL(ide_retry_pc); | 266 | EXPORT_SYMBOL_GPL(ide_retry_pc); |
210 | 267 | ||
@@ -276,7 +333,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
276 | struct ide_cmd *cmd = &hwif->cmd; | 333 | struct ide_cmd *cmd = &hwif->cmd; |
277 | struct request *rq = hwif->rq; | 334 | struct request *rq = hwif->rq; |
278 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 335 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
279 | xfer_func_t *xferfunc; | ||
280 | unsigned int timeout, done; | 336 | unsigned int timeout, done; |
281 | u16 bcount; | 337 | u16 bcount; |
282 | u8 stat, ireason, dsc = 0; | 338 | u8 stat, ireason, dsc = 0; |
@@ -303,11 +359,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
303 | drive->name, rq_data_dir(pc->rq) | 359 | drive->name, rq_data_dir(pc->rq) |
304 | ? "write" : "read"); | 360 | ? "write" : "read"); |
305 | pc->flags |= PC_FLAG_DMA_ERROR; | 361 | pc->flags |= PC_FLAG_DMA_ERROR; |
306 | } else { | 362 | } else |
307 | pc->xferred = pc->req_xfer; | 363 | 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); | 364 | debug_log("%s: DMA finished\n", drive->name); |
312 | } | 365 | } |
313 | 366 | ||
@@ -343,7 +396,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
343 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); | 396 | debug_log("[cmd %x]: check condition\n", rq->cmd[0]); |
344 | 397 | ||
345 | /* Retry operation */ | 398 | /* Retry operation */ |
346 | ide_retry_pc(drive, rq->rq_disk); | 399 | ide_retry_pc(drive); |
347 | 400 | ||
348 | /* queued, but not started */ | 401 | /* queued, but not started */ |
349 | return ide_stopped; | 402 | return ide_stopped; |
@@ -353,6 +406,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) | 406 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) |
354 | dsc = 1; | 407 | dsc = 1; |
355 | 408 | ||
409 | /* | ||
410 | * ->pc_callback() might change rq->data_len for | ||
411 | * residual count, cache total length. | ||
412 | */ | ||
413 | done = blk_rq_bytes(rq); | ||
414 | |||
356 | /* Command finished - Call the callback function */ | 415 | /* Command finished - Call the callback function */ |
357 | uptodate = drive->pc_callback(drive, dsc); | 416 | uptodate = drive->pc_callback(drive, dsc); |
358 | 417 | ||
@@ -361,7 +420,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
361 | 420 | ||
362 | if (blk_special_request(rq)) { | 421 | if (blk_special_request(rq)) { |
363 | rq->errors = 0; | 422 | rq->errors = 0; |
364 | done = blk_rq_bytes(rq); | ||
365 | error = 0; | 423 | error = 0; |
366 | } else { | 424 | } else { |
367 | 425 | ||
@@ -370,11 +428,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
370 | rq->errors = -EIO; | 428 | rq->errors = -EIO; |
371 | } | 429 | } |
372 | 430 | ||
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; | 431 | error = uptodate ? 0 : -EIO; |
379 | } | 432 | } |
380 | 433 | ||
@@ -407,21 +460,11 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) | |||
407 | return ide_do_reset(drive); | 460 | return ide_do_reset(drive); |
408 | } | 461 | } |
409 | 462 | ||
410 | xferfunc = write ? tp_ops->output_data : tp_ops->input_data; | 463 | done = min_t(unsigned int, bcount, cmd->nleft); |
411 | 464 | 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 | 465 | ||
422 | /* Update the current position */ | 466 | /* Update transferred byte count */ |
423 | pc->xferred += done; | 467 | pc->xferred += done; |
424 | pc->cur_pos += done; | ||
425 | 468 | ||
426 | bcount -= done; | 469 | bcount -= done; |
427 | 470 | ||
@@ -599,7 +642,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) | |||
599 | 642 | ||
600 | /* We haven't transferred any data yet */ | 643 | /* We haven't transferred any data yet */ |
601 | pc->xferred = 0; | 644 | pc->xferred = 0; |
602 | pc->cur_pos = pc->buf; | ||
603 | 645 | ||
604 | valid_tf = IDE_VALID_DEVICE; | 646 | valid_tf = IDE_VALID_DEVICE; |
605 | bcount = ((drive->media == ide_tape) ? | 647 | bcount = ((drive->media == ide_tape) ? |