diff options
Diffstat (limited to 'drivers/ide/ide-cd.c')
| -rw-r--r-- | drivers/ide/ide-cd.c | 288 |
1 files changed, 138 insertions, 150 deletions
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 35729a47f797..3aec19d1fdfc 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c | |||
| @@ -265,35 +265,62 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) | |||
| 265 | cdrom_analyze_sense_data(drive, NULL, sense); | 265 | cdrom_analyze_sense_data(drive, NULL, sense); |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | |||
| 268 | /* | 269 | /* |
| 270 | * Allow the drive 5 seconds to recover; some devices will return NOT_READY | ||
| 271 | * while flushing data from cache. | ||
| 272 | * | ||
| 273 | * returns: 0 failed (write timeout expired) | ||
| 274 | * 1 success | ||
| 275 | */ | ||
| 276 | static int ide_cd_breathe(ide_drive_t *drive, struct request *rq) | ||
| 277 | { | ||
| 278 | |||
| 279 | struct cdrom_info *info = drive->driver_data; | ||
| 280 | |||
| 281 | if (!rq->errors) | ||
| 282 | info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY; | ||
| 283 | |||
| 284 | rq->errors = 1; | ||
| 285 | |||
| 286 | if (time_after(jiffies, info->write_timeout)) | ||
| 287 | return 0; | ||
| 288 | else { | ||
| 289 | struct request_queue *q = drive->queue; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | /* | ||
| 293 | * take a breather relying on the unplug timer to kick us again | ||
| 294 | */ | ||
| 295 | |||
| 296 | spin_lock_irqsave(q->queue_lock, flags); | ||
| 297 | blk_plug_device(q); | ||
| 298 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
| 299 | |||
| 300 | return 1; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 269 | * Returns: | 305 | * Returns: |
| 270 | * 0: if the request should be continued. | 306 | * 0: if the request should be continued. |
| 271 | * 1: if the request will be going through error recovery. | 307 | * 1: if the request will be going through error recovery. |
| 272 | * 2: if the request should be ended. | 308 | * 2: if the request should be ended. |
| 273 | */ | 309 | */ |
| 274 | static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) | 310 | static int cdrom_decode_status(ide_drive_t *drive, u8 stat) |
| 275 | { | 311 | { |
| 276 | ide_hwif_t *hwif = drive->hwif; | 312 | ide_hwif_t *hwif = drive->hwif; |
| 277 | struct request *rq = hwif->rq; | 313 | struct request *rq = hwif->rq; |
| 278 | int stat, err, sense_key; | 314 | int err, sense_key, do_end_request = 0; |
| 279 | 315 | u8 quiet = rq->cmd_flags & REQ_QUIET; | |
| 280 | /* check for errors */ | ||
| 281 | stat = hwif->tp_ops->read_status(hwif); | ||
| 282 | |||
| 283 | if (stat_ret) | ||
| 284 | *stat_ret = stat; | ||
| 285 | |||
| 286 | if (OK_STAT(stat, good_stat, BAD_R_STAT)) | ||
| 287 | return 0; | ||
| 288 | 316 | ||
| 289 | /* get the IDE error register */ | 317 | /* get the IDE error register */ |
| 290 | err = ide_read_error(drive); | 318 | err = ide_read_error(drive); |
| 291 | sense_key = err >> 4; | 319 | sense_key = err >> 4; |
| 292 | 320 | ||
| 293 | ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, " | 321 | ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, " |
| 294 | "rq->cmd_type: 0x%x, err: 0x%x", | 322 | "stat 0x%x", |
| 295 | stat, good_stat, rq->cmd[0], rq->cmd_type, | 323 | rq->cmd[0], rq->cmd_type, err, stat); |
| 296 | err); | ||
| 297 | 324 | ||
| 298 | if (blk_sense_request(rq)) { | 325 | if (blk_sense_request(rq)) { |
| 299 | /* | 326 | /* |
| @@ -303,151 +330,108 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) | |||
| 303 | */ | 330 | */ |
| 304 | rq->cmd_flags |= REQ_FAILED; | 331 | rq->cmd_flags |= REQ_FAILED; |
| 305 | return 2; | 332 | return 2; |
| 306 | } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { | 333 | } |
| 307 | /* All other functions, except for READ. */ | ||
| 308 | 334 | ||
| 309 | /* | 335 | /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */ |
| 310 | * if we have an error, pass back CHECK_CONDITION as the | 336 | if (blk_pc_request(rq) && !rq->errors) |
| 311 | * scsi status byte | 337 | rq->errors = SAM_STAT_CHECK_CONDITION; |
| 312 | */ | ||
| 313 | if (blk_pc_request(rq) && !rq->errors) | ||
| 314 | rq->errors = SAM_STAT_CHECK_CONDITION; | ||
| 315 | 338 | ||
| 316 | /* check for tray open */ | 339 | if (blk_noretry_request(rq)) |
| 317 | if (sense_key == NOT_READY) { | 340 | do_end_request = 1; |
| 318 | cdrom_saw_media_change(drive); | 341 | |
| 319 | } else if (sense_key == UNIT_ATTENTION) { | 342 | switch (sense_key) { |
| 320 | /* check for media change */ | 343 | case NOT_READY: |
| 344 | if (blk_fs_request(rq) && rq_data_dir(rq) == WRITE) { | ||
| 345 | if (ide_cd_breathe(drive, rq)) | ||
| 346 | return 1; | ||
| 347 | } else { | ||
| 321 | cdrom_saw_media_change(drive); | 348 | cdrom_saw_media_change(drive); |
| 322 | return 0; | 349 | |
| 323 | } else if (sense_key == ILLEGAL_REQUEST && | 350 | if (blk_fs_request(rq) && !quiet) |
| 324 | rq->cmd[0] == GPCMD_START_STOP_UNIT) { | 351 | printk(KERN_ERR PFX "%s: tray open\n", |
| 325 | /* | 352 | drive->name); |
| 326 | * Don't print error message for this condition-- | ||
| 327 | * SFF8090i indicates that 5/24/00 is the correct | ||
| 328 | * response to a request to close the tray if the | ||
| 329 | * drive doesn't have that capability. | ||
| 330 | * cdrom_log_sense() knows this! | ||
| 331 | */ | ||
| 332 | } else if (!(rq->cmd_flags & REQ_QUIET)) { | ||
| 333 | /* otherwise, print an error */ | ||
| 334 | ide_dump_status(drive, "packet command error", stat); | ||
| 335 | } | 353 | } |
| 354 | do_end_request = 1; | ||
| 355 | break; | ||
| 356 | case UNIT_ATTENTION: | ||
| 357 | cdrom_saw_media_change(drive); | ||
| 336 | 358 | ||
| 337 | rq->cmd_flags |= REQ_FAILED; | 359 | if (blk_fs_request(rq) == 0) |
| 360 | return 0; | ||
| 338 | 361 | ||
| 339 | /* | 362 | /* |
| 340 | * instead of playing games with moving completions around, | 363 | * Arrange to retry the request but be sure to give up if we've |
| 341 | * remove failed request completely and end it when the | 364 | * retried too many times. |
| 342 | * request sense has completed | ||
| 343 | */ | 365 | */ |
| 344 | goto end_request; | 366 | if (++rq->errors > ERROR_MAX) |
| 345 | |||
| 346 | } else if (blk_fs_request(rq)) { | ||
| 347 | int do_end_request = 0; | ||
| 348 | |||
| 349 | /* handle errors from READ and WRITE requests */ | ||
| 350 | |||
| 351 | if (blk_noretry_request(rq)) | ||
| 352 | do_end_request = 1; | 367 | do_end_request = 1; |
| 353 | 368 | break; | |
| 354 | if (sense_key == NOT_READY) { | 369 | case ILLEGAL_REQUEST: |
| 355 | /* tray open */ | 370 | /* |
| 356 | if (rq_data_dir(rq) == READ) { | 371 | * Don't print error message for this condition -- SFF8090i |
| 357 | cdrom_saw_media_change(drive); | 372 | * indicates that 5/24/00 is the correct response to a request |
| 358 | 373 | * to close the tray if the drive doesn't have that capability. | |
| 359 | /* fail the request */ | 374 | * |
| 360 | printk(KERN_ERR PFX "%s: tray open\n", | 375 | * cdrom_log_sense() knows this! |
| 361 | drive->name); | 376 | */ |
| 362 | do_end_request = 1; | 377 | if (rq->cmd[0] == GPCMD_START_STOP_UNIT) |
| 363 | } else { | 378 | break; |
| 364 | struct cdrom_info *info = drive->driver_data; | 379 | /* fall-through */ |
| 365 | 380 | case DATA_PROTECT: | |
| 366 | /* | 381 | /* |
| 367 | * Allow the drive 5 seconds to recover, some | 382 | * No point in retrying after an illegal request or data |
| 368 | * devices will return this error while flushing | 383 | * protect error. |
| 369 | * data from cache. | 384 | */ |
| 370 | */ | 385 | if (!quiet) |
| 371 | if (!rq->errors) | ||
| 372 | info->write_timeout = jiffies + | ||
| 373 | ATAPI_WAIT_WRITE_BUSY; | ||
| 374 | rq->errors = 1; | ||
| 375 | if (time_after(jiffies, info->write_timeout)) | ||
| 376 | do_end_request = 1; | ||
| 377 | else { | ||
| 378 | struct request_queue *q = drive->queue; | ||
| 379 | unsigned long flags; | ||
| 380 | |||
| 381 | /* | ||
| 382 | * take a breather relying on the unplug | ||
| 383 | * timer to kick us again | ||
| 384 | */ | ||
| 385 | spin_lock_irqsave(q->queue_lock, flags); | ||
| 386 | blk_plug_device(q); | ||
| 387 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
| 388 | |||
| 389 | return 1; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | } else if (sense_key == UNIT_ATTENTION) { | ||
| 393 | /* media change */ | ||
| 394 | cdrom_saw_media_change(drive); | ||
| 395 | |||
| 396 | /* | ||
| 397 | * Arrange to retry the request but be sure to give up | ||
| 398 | * if we've retried too many times. | ||
| 399 | */ | ||
| 400 | if (++rq->errors > ERROR_MAX) | ||
| 401 | do_end_request = 1; | ||
| 402 | } else if (sense_key == ILLEGAL_REQUEST || | ||
| 403 | sense_key == DATA_PROTECT) { | ||
| 404 | /* | ||
| 405 | * No point in retrying after an illegal request or data | ||
| 406 | * protect error. | ||
| 407 | */ | ||
| 408 | ide_dump_status(drive, "command error", stat); | 386 | ide_dump_status(drive, "command error", stat); |
| 409 | do_end_request = 1; | 387 | do_end_request = 1; |
| 410 | } else if (sense_key == MEDIUM_ERROR) { | 388 | break; |
| 411 | /* | 389 | case MEDIUM_ERROR: |
| 412 | * No point in re-trying a zillion times on a bad | 390 | /* |
| 413 | * sector. If we got here the error is not correctable. | 391 | * No point in re-trying a zillion times on a bad sector. |
| 414 | */ | 392 | * If we got here the error is not correctable. |
| 415 | ide_dump_status(drive, "media error (bad sector)", | 393 | */ |
| 394 | if (!quiet) | ||
| 395 | ide_dump_status(drive, "media error " | ||
| 396 | "(bad sector)", stat); | ||
| 397 | do_end_request = 1; | ||
| 398 | break; | ||
| 399 | case BLANK_CHECK: | ||
| 400 | /* disk appears blank? */ | ||
| 401 | if (!quiet) | ||
| 402 | ide_dump_status(drive, "media error (blank)", | ||
| 416 | stat); | 403 | stat); |
| 417 | do_end_request = 1; | 404 | do_end_request = 1; |
| 418 | } else if (sense_key == BLANK_CHECK) { | 405 | break; |
| 419 | /* disk appears blank ?? */ | 406 | default: |
| 420 | ide_dump_status(drive, "media error (blank)", stat); | 407 | if (blk_fs_request(rq) == 0) |
| 421 | do_end_request = 1; | 408 | break; |
| 422 | } else if ((err & ~ATA_ABORTED) != 0) { | 409 | if (err & ~ATA_ABORTED) { |
| 423 | /* go to the default handler for other errors */ | 410 | /* go to the default handler for other errors */ |
| 424 | ide_error(drive, "cdrom_decode_status", stat); | 411 | ide_error(drive, "cdrom_decode_status", stat); |
| 425 | return 1; | 412 | return 1; |
| 426 | } else if ((++rq->errors > ERROR_MAX)) { | 413 | } else if (++rq->errors > ERROR_MAX) |
| 427 | /* we've racked up too many retries, abort */ | 414 | /* we've racked up too many retries, abort */ |
| 428 | do_end_request = 1; | 415 | do_end_request = 1; |
| 429 | } | 416 | } |
| 430 | |||
| 431 | /* | ||
| 432 | * End a request through request sense analysis when we have | ||
| 433 | * sense data. We need this in order to perform end of media | ||
| 434 | * processing. | ||
| 435 | */ | ||
| 436 | if (do_end_request) | ||
| 437 | goto end_request; | ||
| 438 | 417 | ||
| 439 | /* | 418 | if (blk_fs_request(rq) == 0) { |
| 440 | * If we got a CHECK_CONDITION status, queue | 419 | rq->cmd_flags |= REQ_FAILED; |
| 441 | * a request sense command. | 420 | do_end_request = 1; |
| 442 | */ | ||
| 443 | if (stat & ATA_ERR) | ||
| 444 | cdrom_queue_request_sense(drive, NULL, NULL); | ||
| 445 | return 1; | ||
| 446 | } else { | ||
| 447 | blk_dump_rq_flags(rq, PFX "bad rq"); | ||
| 448 | return 2; | ||
| 449 | } | 421 | } |
| 450 | 422 | ||
| 423 | /* | ||
| 424 | * End a request through request sense analysis when we have sense data. | ||
| 425 | * We need this in order to perform end of media processing. | ||
| 426 | */ | ||
| 427 | if (do_end_request) | ||
| 428 | goto end_request; | ||
| 429 | |||
| 430 | /* if we got a CHECK_CONDITION status, queue a request sense command */ | ||
| 431 | if (stat & ATA_ERR) | ||
| 432 | cdrom_queue_request_sense(drive, NULL, NULL); | ||
| 433 | return 1; | ||
| 434 | |||
| 451 | end_request: | 435 | end_request: |
| 452 | if (stat & ATA_ERR) { | 436 | if (stat & ATA_ERR) { |
| 453 | struct request_queue *q = drive->queue; | 437 | struct request_queue *q = drive->queue; |
| @@ -624,15 +608,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
| 624 | struct ide_cmd *cmd = &hwif->cmd; | 608 | struct ide_cmd *cmd = &hwif->cmd; |
| 625 | struct request *rq = hwif->rq; | 609 | struct request *rq = hwif->rq; |
| 626 | ide_expiry_t *expiry = NULL; | 610 | ide_expiry_t *expiry = NULL; |
| 627 | int dma_error = 0, dma, stat, thislen, uptodate = 0; | 611 | int dma_error = 0, dma, thislen, uptodate = 0; |
| 628 | int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors; | 612 | int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors; |
| 629 | int sense = blk_sense_request(rq); | 613 | int sense = blk_sense_request(rq); |
| 630 | unsigned int timeout; | 614 | unsigned int timeout; |
| 631 | u16 len; | 615 | u16 len; |
| 632 | u8 ireason; | 616 | u8 ireason, stat; |
| 633 | 617 | ||
| 634 | ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x", | 618 | ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write); |
| 635 | rq->cmd[0], write); | ||
| 636 | 619 | ||
| 637 | /* check for errors */ | 620 | /* check for errors */ |
| 638 | dma = drive->dma; | 621 | dma = drive->dma; |
| @@ -648,11 +631,16 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
| 648 | } | 631 | } |
| 649 | } | 632 | } |
| 650 | 633 | ||
| 651 | rc = cdrom_decode_status(drive, 0, &stat); | 634 | /* check status */ |
| 652 | if (rc) { | 635 | stat = hwif->tp_ops->read_status(hwif); |
| 653 | if (rc == 2) | 636 | |
| 654 | goto out_end; | 637 | if (!OK_STAT(stat, 0, BAD_R_STAT)) { |
| 655 | return ide_stopped; | 638 | rc = cdrom_decode_status(drive, stat); |
| 639 | if (rc) { | ||
| 640 | if (rc == 2) | ||
| 641 | goto out_end; | ||
| 642 | return ide_stopped; | ||
| 643 | } | ||
| 656 | } | 644 | } |
| 657 | 645 | ||
| 658 | /* using dma, transfer is complete now */ | 646 | /* using dma, transfer is complete now */ |
