📄 ide-cd.c
字号:
unsigned long sector; unsigned long bio_sectors; unsigned long valid; struct cdrom_info *info = drive->driver_data; if (!cdrom_log_sense(drive, failed_command, sense)) return; /* * If a read toc is executed for a CD-R or CD-RW medium where * the first toc has not been recorded yet, it will fail with * 05/24/00 (which is a confusing error) */ if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP) if (sense->sense_key == 0x05 && sense->asc == 0x24) return; if (sense->error_code == 0x70) { /* Current Error */ switch(sense->sense_key) { case MEDIUM_ERROR: case VOLUME_OVERFLOW: case ILLEGAL_REQUEST: if (!sense->valid) break; if (failed_command == NULL || !blk_fs_request(failed_command)) break; sector = (sense->information[0] << 24) | (sense->information[1] << 16) | (sense->information[2] << 8) | (sense->information[3]); bio_sectors = bio_sectors(failed_command->bio); if (bio_sectors < 4) bio_sectors = 4; if (drive->queue->hardsect_size == 2048) sector <<= 2; /* Device sector size is 2K */ sector &= ~(bio_sectors -1); valid = (sector - failed_command->sector) << 9; if (valid < 0) valid = 0; if (sector < get_capacity(info->disk) && drive->probed_capacity - sector < 4 * 75) { set_capacity(info->disk, sector); } } }#if VERBOSE_IDE_CD_ERRORS { int i; const char *s = "bad sense key!"; char buf[80]; printk ("ATAPI device %s:\n", drive->name); if (sense->error_code==0x70) printk(" Error: "); else if (sense->error_code==0x71) printk(" Deferred Error: "); else if (sense->error_code == 0x7f) printk(" Vendor-specific Error: "); else printk(" Unknown Error Type: "); if (sense->sense_key < ARRAY_SIZE(sense_key_texts)) s = sense_key_texts[sense->sense_key]; printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); if (sense->asc == 0x40) { sprintf(buf, "Diagnostic failure on component 0x%02x", sense->ascq); s = buf; } else { int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts); unsigned long key = (sense->sense_key << 16); key |= (sense->asc << 8); if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) key |= sense->ascq; s = NULL; while (hi > lo) { mid = (lo + hi) / 2; if (sense_data_texts[mid].asc_ascq == key || sense_data_texts[mid].asc_ascq == (0xff0000|key)) { s = sense_data_texts[mid].text; break; } else if (sense_data_texts[mid].asc_ascq > key) hi = mid; else lo = mid+1; } } if (s == NULL) { if (sense->asc > 0x80) s = "(vendor-specific error)"; else s = "(reserved error code)"; } printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", s, sense->asc, sense->ascq); if (failed_command != NULL) { int lo=0, mid, hi= ARRAY_SIZE(packet_command_texts); s = NULL; while (hi > lo) { mid = (lo + hi) / 2; if (packet_command_texts[mid].packet_command == failed_command->cmd[0]) { s = packet_command_texts[mid].text; break; } if (packet_command_texts[mid].packet_command > failed_command->cmd[0]) hi = mid; else lo = mid+1; } printk (KERN_ERR " The failed \"%s\" packet command was: \n \"", s); for (i=0; i<sizeof (failed_command->cmd); i++) printk ("%02x ", failed_command->cmd[i]); printk ("\"\n"); } /* The SKSV bit specifies validity of the sense_key_specific * in the next two commands. It is bit 7 of the first byte. * In the case of NOT_READY, if SKSV is set the drive can * give us nice ETA readings. */ if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; printk(KERN_ERR " Command is %02d%% complete\n", progress / 0xffff); } if (sense->sense_key == ILLEGAL_REQUEST && (sense->sks[0] & 0x80) != 0) { printk(KERN_ERR " Error in %s byte %d", (sense->sks[0] & 0x40) != 0 ? "command packet" : "command data", (sense->sks[1] << 8) + sense->sks[2]); if ((sense->sks[0] & 0x40) != 0) printk (" bit %d", sense->sks[0] & 0x07); printk ("\n"); } }#else /* not VERBOSE_IDE_CD_ERRORS */ /* Suppress printing unit attention and `in progress of becoming ready' errors when we're not being verbose. */ if (sense->sense_key == UNIT_ATTENTION || (sense->sense_key == NOT_READY && (sense->asc == 4 || sense->asc == 0x3a))) return; printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n", drive->name, sense->error_code, sense->sense_key, sense->asc, sense->ascq);#endif /* not VERBOSE_IDE_CD_ERRORS */}/* * Initialize a ide-cd packet command request */static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq){ struct cdrom_info *cd = drive->driver_data; ide_init_drive_cmd(rq); rq->cmd_type = REQ_TYPE_ATA_PC; rq->rq_disk = cd->disk;}static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, struct request *failed_command){ struct cdrom_info *info = drive->driver_data; struct request *rq = &info->request_sense_request; if (sense == NULL) sense = &info->sense_data; /* stuff the sense request in front of our current request */ cdrom_prepare_request(drive, rq); rq->data = sense; rq->cmd[0] = GPCMD_REQUEST_SENSE; rq->cmd[4] = rq->data_len = 18; rq->cmd_type = REQ_TYPE_SENSE; /* NOTE! Save the failed command in "rq->buffer" */ rq->buffer = (void *) failed_command; (void) ide_do_drive_cmd(drive, rq, ide_preempt);}static void cdrom_end_request (ide_drive_t *drive, int uptodate){ struct request *rq = HWGROUP(drive)->rq; int nsectors = rq->hard_cur_sectors; if (blk_sense_request(rq) && uptodate) { /* * For REQ_TYPE_SENSE, "rq->buffer" points to the original * failed request */ struct request *failed = (struct request *) rq->buffer; struct cdrom_info *info = drive->driver_data; void *sense = &info->sense_data; unsigned long flags; if (failed) { if (failed->sense) { sense = failed->sense; failed->sense_len = rq->sense_len; } cdrom_analyze_sense_data(drive, failed, sense); /* * now end failed request */ if (blk_fs_request(failed)) { if (ide_end_dequeued_request(drive, failed, 0, failed->hard_nr_sectors)) BUG(); } else { spin_lock_irqsave(&ide_lock, flags); end_that_request_chunk(failed, 0, failed->data_len); end_that_request_last(failed, 0); spin_unlock_irqrestore(&ide_lock, flags); } } else cdrom_analyze_sense_data(drive, NULL, sense); } if (!rq->current_nr_sectors && blk_fs_request(rq)) uptodate = 1; /* make sure it's fully ended */ if (blk_pc_request(rq)) nsectors = (rq->data_len + 511) >> 9; if (!nsectors) nsectors = 1; ide_end_request(drive, uptodate, nsectors);}static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat){ if (stat & 0x80) return; ide_dump_status(drive, msg, stat);}/* Returns 0 if the request should be continued. Returns 1 if the request was ended. */static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret){ struct request *rq = HWGROUP(drive)->rq; int stat, err, sense_key; /* Check for errors. */ stat = HWIF(drive)->INB(IDE_STATUS_REG); if (stat_ret) *stat_ret = stat; if (OK_STAT(stat, good_stat, BAD_R_STAT)) return 0; /* Get the IDE error register. */ err = HWIF(drive)->INB(IDE_ERROR_REG); sense_key = err >> 4; if (rq == NULL) { printk("%s: missing rq in cdrom_decode_status\n", drive->name); return 1; } if (blk_sense_request(rq)) { /* We got an error trying to get sense info from the drive (probably while trying to recover from a former error). Just give up. */ rq->cmd_flags |= REQ_FAILED; cdrom_end_request(drive, 0); ide_error(drive, "request sense failure", stat); return 1; } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { /* All other functions, except for READ. */ unsigned long flags; /* * if we have an error, pass back CHECK_CONDITION as the * scsi status byte */ if (blk_pc_request(rq) && !rq->errors) rq->errors = SAM_STAT_CHECK_CONDITION; /* Check for tray open. */ if (sense_key == NOT_READY) { cdrom_saw_media_change (drive); } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); /*printk("%s: media changed\n",drive->name);*/ return 0; } else if ((sense_key == ILLEGAL_REQUEST) && (rq->cmd[0] == GPCMD_START_STOP_UNIT)) { /* * Don't print error message for this condition-- * SFF8090i indicates that 5/24/00 is the correct * response to a request to close the tray if the * drive doesn't have that capability. * cdrom_log_sense() knows this! */ } else if (!(rq->cmd_flags & REQ_QUIET)) { /* Otherwise, print an error. */ ide_dump_status(drive, "packet command error", stat); } rq->cmd_flags |= REQ_FAILED; /* * instead of playing games with moving completions around, * remove failed request completely and end it when the * request sense has completed */ if (stat & ERR_STAT) { spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; spin_unlock_irqrestore(&ide_lock, flags); cdrom_queue_request_sense(drive, rq->sense, rq); } else cdrom_end_request(drive, 0); } else if (blk_fs_request(rq)) { int do_end_request = 0; /* Handle errors from READ and WRITE requests. */ if (blk_noretry_request(rq)) do_end_request = 1; if (sense_key == NOT_READY) { /* Tray open. */ if (rq_data_dir(rq) == READ) { cdrom_saw_media_change (drive); /* Fail the request. */ printk ("%s: tray open\n", drive->name); do_end_request = 1; } else { struct cdrom_info *info = drive->driver_data; /* allow the drive 5 seconds to recover, some * devices will return this error while flushing * data from cache */ if (!rq->errors) info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY; rq->errors = 1; if (time_after(jiffies, info->write_timeout)) do_end_request = 1; else { unsigned long flags; /* * take a breather relying on the * unplug timer to kick us again */ spin_lock_irqsave(&ide_lock, flags); blk_plug_device(drive->queue); spin_unlock_irqrestore(&ide_lock,flags); return 1; } } } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ cdrom_saw_media_change (drive); /* Arrange to retry the request. But be sure to give up if we've retried too many times. */ if (++rq->errors > ERROR_MAX) do_end_request = 1; } else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT) { /* No point in retrying after an illegal request or data protect error.*/ ide_dump_status_no_sense (drive, "command error", stat); do_end_request = 1; } else if (sense_key == MEDIUM_ERROR) { /* No point in re-trying a zillion times on a bad * sector... If we got here the error is not correctable */ ide_dump_status_no_sense (drive, "media error (bad sector)", stat); do_end_request = 1; } else if (sense_key == BLANK_CHECK) { /* Disk appears blank ?? */ ide_dump_status_no_sense (drive, "media error (blank)", stat); do_end_request = 1; } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler for other errors. */ ide_error(drive, "cdrom_decode_status", stat); return 1; } else if ((++rq->errors > ERROR_MAX)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -