📄 scsi_base.c
字号:
* if under full steam (interrupts) it will return: * SUCCESSFULLY_QUEUED, will do a wakeup when complete * TRY_AGAIN_LATER, (as for polling) * After the wakeup, we must still check if it succeeded * * If we have a SCSI_NOSLEEP (typically because we have a buf) * we just return. All the error proccessing and the buffer * code both expect us to return straight to them, so as soon * as the command is queued, return. */ switch ((*(xs->sc_link->adapter->scsi_cmd)) (xs)) { case SUCCESSFULLY_QUEUED: if ((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) return EJUSTRETURN;#ifdef DIAGNOSTIC if (xs->flags & SCSI_NOSLEEP) panic("scsi_execute_xs: NOSLEEP and POLL");#endif s = splbio(); while ((xs->flags & ITSDONE) == 0) { tsleep(xs, PRIBIO + 1, "scsi_scsi_cmd", 0); } splx(s); case COMPLETE: /* Polling command completed ok */ if (xs->bp) return EJUSTRETURN; doit: SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n")); if ((error = sc_err1(xs, 0)) != ERESTART) return error; goto retry; case TRY_AGAIN_LATER: /* adapter resource shortage */ xs->error = XS_BUSY; goto doit; default: panic("scsi_execute_xs: invalid return code"); }#ifdef DIAGNOSTIC panic("scsi_execute_xs: impossible");#endif return EINVAL;}/* * ask the scsi driver to perform a command for us. * tell it where to read/write the data, and how * long the data is supposed to be. If we have a buf * to associate with the transfer, we need that too. */int scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen, retries, timeout, bp, flags) struct scsi_link *sc_link; struct scsi_generic *scsi_cmd; int cmdlen; u_char *data_addr; int datalen; int retries; int timeout; struct buf *bp; int flags;{ struct scsi_xfer *xs; int error; SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));#ifdef DIAGNOSTIC if (bp != 0 && (flags & SCSI_NOSLEEP) == 0) panic("scsi_scsi_cmd: buffer without nosleep");#endif if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen, retries, timeout, bp, flags)) == NULL) return ENOMEM; if ((error = scsi_execute_xs(xs)) == EJUSTRETURN) { return 0; } /* * we have finished with the xfer stuct, free it and * check if anyone else needs to be started up. */ scsi_free_xs(xs, flags); return error;}int sc_err1(xs, async) struct scsi_xfer *xs; int async;{ int error; SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error)); /* * If it has a buf, we might be working with * a request from the buffer cache or some other * piece of code that requires us to process * errors at interrupt time. We have probably * been called by scsi_done() */ switch (xs->error) { case XS_NOERROR: /* nearly always hit this one */ error = 0; break; case XS_SENSE: case XS_SHORTSENSE: if ((error = scsi_interpret_sense(xs)) == ERESTART) { if (xs->error == XS_BUSY) { xs->error = XS_SENSE; goto sense_retry; } goto retry; } SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_interpret_sense returned %d\n", error)); break; case XS_BUSY: sense_retry: if (xs->retries) { if ((xs->flags & SCSI_POLL) != 0) delay(1000000);#if 0 else if ((xs->flags & SCSI_NOSLEEP) == 0) { tsleep(&lbolt, PRIBIO, "scbusy", 0); }#endif else {#if 0 timeout(scsi_requeue, xs, hz);#else goto lose;#endif } } case XS_TIMEOUT: retry: if (xs->retries--) { xs->error = XS_NOERROR; xs->flags &= ~ITSDONE; return ERESTART; } case XS_DRIVER_STUFFUP: lose: error = EIO; break; case XS_SELTIMEOUT: /* XXX Disable device? */ error = EIO; break; case XS_RESET: if (xs->retries) { SC_DEBUG(xs->sc_link, SDEV_DB3, ("restarting command destroyed by reset\n")); goto retry; } error = EIO; break; default: sc_print_addr(xs->sc_link); printf("unknown error category from scsi driver\n"); error = EIO; break; } return error;}/* * Look at the returned sense and act on the error, determining * the unix error number to pass back. (0 = report no error) * * THIS IS THE DEFAULT ERROR HANDLER */int scsi_interpret_sense(xs) struct scsi_xfer *xs;{ struct scsi_sense_data *sense; struct scsi_link *sc_link = xs->sc_link; u_int8_t key; u_int32_t info; int error; sense = &xs->sense;#ifdef SCSIDEBUG if ((sc_link->flags & SDEV_DB1) != 0) { int count; printf("code%x valid%x ", sense->error_code & SSD_ERRCODE, sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); printf("seg%x key%x ili%x eom%x fmark%x\n", sense->segment, sense->flags & SSD_KEY, sense->flags & SSD_ILI ? 1 : 0, sense->flags & SSD_EOM ? 1 : 0, sense->flags & SSD_FILEMARK ? 1 : 0); printf("info: %x %x %x %x followed by %d extra bytes\n", sense->info[0], sense->info[1], sense->info[2], sense->info[3], sense->extra_len); printf("extra: "); for (count = 0; count < sense->extra_len; count++) printf("%x ", sense->cmd_spec_info[count]); printf("\n"); }#endif /* SCSIDEBUG */ /* * If the device has it's own error handler, call it first. * If it returns a legit error value, return that, otherwise * it wants us to continue with normal error processing. */ if (sc_link->device->err_handler) { SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n")); error = (*sc_link->device->err_handler) (xs); if (error != SCSIRET_CONTINUE) return error; /* error >= 0 better ? */ } /* otherwise use the default */ switch (sense->error_code & SSD_ERRCODE) { /* * If it's code 70, use the extended stuff and interpret the key */ case 0x71: /* delayed error */ sc_print_addr(sc_link); key = sense->flags & SSD_KEY; printf(" DEFERRED ERROR, key = 0x%x\n", key); /* FALLTHROUGH */ case 0x70: if ((sense->error_code & SSD_ERRCODE_VALID) != 0) info = _4btol(sense->info); else info = 0; key = sense->flags & SSD_KEY; switch (key) { case SKEY_NO_SENSE: case SKEY_RECOVERED_ERROR: if (xs->resid == xs->datalen) xs->resid = 0; /* not short read */ case SKEY_EQUAL: error = 0; break; case SKEY_NOT_READY: if ((sc_link->flags & SDEV_REMOVABLE) != 0) sc_link->flags &= ~SDEV_MEDIA_LOADED; if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0) return 0; if (xs->retries && sense->add_sense_code == 0x04 && sense->add_sense_code_qual == 0x01) { xs->error = XS_BUSY; /* ie. sense_retry */ return ERESTART; } if (xs->retries && !(sc_link->flags & SDEV_REMOVABLE)) { delay(1000000); return ERESTART; } if ((xs->flags & SCSI_SILENT) != 0) return EIO; error = EIO; break; case SKEY_ILLEGAL_REQUEST: if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0) return 0; if ((xs->flags & SCSI_SILENT) != 0) return EIO; error = EINVAL; break; case SKEY_UNIT_ATTENTION: if (sense->add_sense_code == 0x29 && sense->add_sense_code_qual == 0x00) return (ERESTART); /* device or bus reset */ if ((sc_link->flags & SDEV_REMOVABLE) != 0) sc_link->flags &= ~SDEV_MEDIA_LOADED; if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 || /* XXX Should reupload any transient state. */ (sc_link->flags & SDEV_REMOVABLE) == 0) return ERESTART; if ((xs->flags & SCSI_SILENT) != 0) return EIO; error = EIO; break; case SKEY_WRITE_PROTECT: error = EROFS; break; case SKEY_BLANK_CHECK: error = 0; break; case SKEY_ABORTED_COMMAND: error = ERESTART; break; case SKEY_VOLUME_OVERFLOW: error = ENOSPC; break; default: error = EIO; break; } if ((xs->flags & SCSI_SILENT) == 0) scsi_print_sense(xs, 0); return error; /* * Not code 70, just report it */ default: sc_print_addr(sc_link); printf("Sense Error Code %d", sense->error_code & SSD_ERRCODE); if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { struct scsi_sense_data_unextended *usense = (struct scsi_sense_data_unextended *)sense; printf(" at block no. %d (decimal)", _3btol(usense->block)); } printf("\n"); return EIO; }}/* * Utility routines often used in SCSI stuff *//* * Print out the scsi_link structure's address info. */voidsc_print_addr(sc_link) struct scsi_link *sc_link;{ printf("%s(%s:%d:%d): ", sc_link->device_softc ? ((struct device *)sc_link->device_softc)->dv_xname : "probe", ((struct device *)sc_link->adapter_softc)->dv_xname, sc_link->target, sc_link->lun); }static const char *sense_keys[16] = { "No Additional Sense", "Soft Error", "Not Ready", "Media Error", "Hardware Error", "Illegal Request", "Unit Attention", "Write Protected", "Blank Check", "Vendor Unique", "Copy Aborted", "Aborted Command", "Equal Error", "Volume Overflow", "Miscompare Error", "Reserved"};#ifndef SCSITERSEstatic const struct { u_char asc, ascq; char *description;} adesc[] = { { 0x00, 0x00, "No Additional Sense Information" }, { 0x00, 0x01, "Filemark Detected" }, { 0x00, 0x02, "End-Of-Partition/Medium Detected" }, { 0x00, 0x03, "Setmark Detected" }, { 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" }, { 0x00, 0x05, "End-Of-Data Detected" }, { 0x00, 0x06, "I/O Process Terminated" }, { 0x00, 0x11, "Audio Play Operation In Progress" }, { 0x00, 0x12, "Audio Play Operation Paused" }, { 0x00, 0x13, "Audio Play Operation Successfully Completed" }, { 0x00, 0x14, "Audio Play Operation Stopped Due to Error" }, { 0x00, 0x15, "No Current Audio Status To Return" }, { 0x01, 0x00, "No Index/Sector Signal" }, { 0x02, 0x00, "No Seek Complete" }, { 0x03, 0x00, "Peripheral Device Write Fault" }, { 0x03, 0x01, "No Write Current" }, { 0x03, 0x02, "Excessive Write Errors" }, { 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" }, { 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" }, { 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" }, { 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" }, { 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" }, { 0x05, 0x00, "Logical Unit Does Not Respond To Selection" }, { 0x06, 0x00, "No Reference Position Found" }, { 0x07, 0x00, "Multiple Peripheral Devices Selected" }, { 0x08, 0x00, "Logical Unit Communication Failure" }, { 0x08, 0x01, "Logical Unit Communication Timeout" }, { 0x08, 0x02, "Logical Unit Communication Parity Error" }, { 0x09, 0x00, "Track Following Error" }, { 0x09, 0x01, "Tracking Servo Failure" }, { 0x09, 0x02, "Focus Servo Failure" }, { 0x09, 0x03, "Spindle Servo Failure" }, { 0x0A, 0x00, "Error Log Overflow" }, { 0x0C, 0x00, "Write Error" }, { 0x0C, 0x01, "Write Error Recovered with Auto Reallocation" }, { 0x0C, 0x02, "Write Error - Auto Reallocate Failed" }, { 0x10, 0x00, "ID CRC Or ECC Error" }, { 0x11, 0x00, "Unrecovered Read Error" }, { 0x11, 0x01, "Read Retried Exhausted" }, { 0x11, 0x02, "Error Too Long To Correct" }, { 0x11, 0x03, "Multiple Read Errors" }, { 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" }, { 0x11, 0x05, "L-EC Uncorrectable Error" }, { 0x11, 0x06, "CIRC Unrecovered Error" }, { 0x11, 0x07, "Data Resynchronization Error" }, { 0x11, 0x08, "Incomplete Block Found" }, { 0x11, 0x09, "No Gap Found" }, { 0x11, 0x0A, "Miscorrected Error" }, { 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -