📄 aiclib.c
字号:
&sense_entry, &asc_entry); *sense_key_desc = sense_entry->desc; if (asc_entry != NULL) *asc_desc = asc_entry->desc; else if (asc >= 0x80 && asc <= 0xff) *asc_desc = "Vendor Specific ASC"; else if (ascq >= 0x80 && ascq <= 0xff) *asc_desc = "Vendor Specific ASCQ"; else *asc_desc = "Reserved ASC/ASCQ pair";}/* * Given sense and device type information, return the appropriate action. * If we do not understand the specific error as identified by the ASC/ASCQ * pair, fall back on the more generic actions derived from the sense key. */aic_sense_actionaic_sense_error_action(struct scsi_sense_data *sense_data, struct scsi_inquiry_data *inq_data, uint32_t sense_flags){ const struct asc_table_entry *asc_entry; const struct sense_key_table_entry *sense_entry; int error_code, sense_key, asc, ascq; aic_sense_action action; scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); if (error_code == SSD_DEFERRED_ERROR) { /* * XXX dufault@FreeBSD.org * This error doesn't relate to the command associated * with this request sense. A deferred error is an error * for a command that has already returned GOOD status * (see SCSI2 8.2.14.2). * * By my reading of that section, it looks like the current * command has been cancelled, we should now clean things up * (hopefully recovering any lost data) and then retry the * current command. There are two easy choices, both wrong: * * 1. Drop through (like we had been doing), thus treating * this as if the error were for the current command and * return and stop the current command. * * 2. Issue a retry (like I made it do) thus hopefully * recovering the current transfer, and ignoring the * fact that we've dropped a command. * * These should probably be handled in a device specific * sense handler or punted back up to a user mode daemon */ action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; } else { fetchtableentries(sense_key, asc, ascq, inq_data, &sense_entry, &asc_entry); /* * Override the 'No additional Sense' entry (0,0) * with the error action of the sense key. */ if (asc_entry != NULL && (asc != 0 || ascq != 0)) action = asc_entry->action; else action = sense_entry->action; if (sense_key == SSD_KEY_RECOVERED_ERROR) { /* * The action succeeded but the device wants * the user to know that some recovery action * was required. */ action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); action |= SS_NOP|SSQ_PRINT_SENSE; } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { if ((sense_flags & SF_QUIET_IR) != 0) action &= ~SSQ_PRINT_SENSE; } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { if ((sense_flags & SF_RETRY_UA) != 0 && (action & SS_MASK) == SS_FAIL) { action &= ~(SS_MASK|SSQ_MASK); action |= SS_RETRY|SSQ_DECREMENT_COUNT| SSQ_PRINT_SENSE; } } } if ((sense_flags & SF_PRINT_ALWAYS) != 0) action |= SSQ_PRINT_SENSE; else if ((sense_flags & SF_NO_PRINT) != 0) action &= ~SSQ_PRINT_SENSE; return (action);}/* * Try make as good a match as possible with * available sub drivers */intaic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry){ struct scsi_inquiry_pattern *entry; struct scsi_inquiry_data *inq; entry = (struct scsi_inquiry_pattern *)table_entry; inq = (struct scsi_inquiry_data *)inqbuffer; if (((SID_TYPE(inq) == entry->type) || (entry->type == T_ANY)) && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE : entry->media_type & SIP_MEDIA_FIXED) && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) && (cam_strmatch(inq->product, entry->product, sizeof(inq->product)) == 0) && (cam_strmatch(inq->revision, entry->revision, sizeof(inq->revision)) == 0)) { return (0); } return (-1);}/* * Table of syncrates that don't follow the "divisible by 4" * rule. This table will be expanded in future SCSI specs. */static struct { u_int period_factor; u_int period; /* in 100ths of ns */} scsi_syncrates[] = { { 0x08, 625 }, /* FAST-160 */ { 0x09, 1250 }, /* FAST-80 */ { 0x0a, 2500 }, /* FAST-40 40MHz */ { 0x0b, 3030 }, /* FAST-40 33MHz */ { 0x0c, 5000 } /* FAST-20 */};/* * Return the frequency in kHz corresponding to the given * sync period factor. */u_intaic_calc_syncsrate(u_int period_factor){ int i; int num_syncrates; num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); /* See if the period is in the "exception" table */ for (i = 0; i < num_syncrates; i++) { if (period_factor == scsi_syncrates[i].period_factor) { /* Period in kHz */ return (100000000 / scsi_syncrates[i].period); } } /* * Wasn't in the table, so use the standard * 4 times conversion. */ return (10000000 / (period_factor * 4 * 10));}/* * Return speed in KB/s. */u_intaic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate){ u_int freq; if (offset != 0 && period < min_rate) freq = aic_calc_syncsrate(period); else /* Roughly 3.3MB/s for async */ freq = 3300; freq <<= width; return (freq);}uint32_taic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data, cam_status status, u_int scsi_status){ aic_sense_action err_action; int sense; sense = (cmd->result >> 24) == DRIVER_SENSE; switch (status) { case CAM_REQ_CMP: err_action = SS_NOP; break; case CAM_AUTOSENSE_FAIL: case CAM_SCSI_STATUS_ERROR: switch (scsi_status) { case SCSI_STATUS_OK: case SCSI_STATUS_COND_MET: case SCSI_STATUS_INTERMED: case SCSI_STATUS_INTERMED_COND_MET: err_action = SS_NOP; break; case SCSI_STATUS_CMD_TERMINATED: case SCSI_STATUS_CHECK_COND: if (sense != 0) { struct scsi_sense_data *sense; sense = (struct scsi_sense_data *) &cmd->sense_buffer; err_action = aic_sense_error_action(sense, inq_data, 0); } else { err_action = SS_RETRY|SSQ_FALLBACK | SSQ_DECREMENT_COUNT|EIO; } break; case SCSI_STATUS_QUEUE_FULL: case SCSI_STATUS_BUSY: err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY | SSQ_DECREMENT_COUNT|EBUSY; break; case SCSI_STATUS_RESERV_CONFLICT: default: err_action = SS_FAIL|EBUSY; break; } break; case CAM_CMD_TIMEOUT: case CAM_REQ_CMP_ERR: case CAM_UNEXP_BUSFREE: case CAM_UNCOR_PARITY: case CAM_DATA_RUN_ERR: err_action = SS_RETRY|SSQ_FALLBACK|EIO; break; case CAM_UA_ABORT: case CAM_UA_TERMIO: case CAM_MSG_REJECT_REC: case CAM_SEL_TIMEOUT: err_action = SS_FAIL|EIO; break; case CAM_REQ_INVALID: case CAM_PATH_INVALID: case CAM_DEV_NOT_THERE: case CAM_NO_HBA: case CAM_PROVIDE_FAIL: case CAM_REQ_TOO_BIG: case CAM_RESRC_UNAVAIL: case CAM_BUSY: default: /* panic?? These should never occur in our application. */ err_action = SS_FAIL|EIO; break; case CAM_SCSI_BUS_RESET: case CAM_BDR_SENT: case CAM_REQUEUE_REQ: /* Unconditional requeue */ err_action = SS_RETRY; break; } return (err_action);}char *aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, aic_option_callback_t *callback, u_long callback_arg){ char *tok_end; char *tok_end2; int i; int instance; int targ; int done; char tok_list[] = {'.', ',', '{', '}', '\0'}; /* All options use a ':' name/arg separator */ if (*opt_arg != ':') return (opt_arg); opt_arg++; instance = -1; targ = -1; done = FALSE; /* * Restore separator that may be in * the middle of our option argument. */ tok_end = strchr(opt_arg, '\0'); if (tok_end < end) *tok_end = ','; while (!done) { switch (*opt_arg) { case '{': if (instance == -1) { instance = 0; } else { if (depth > 1) { if (targ == -1) targ = 0; } else { printf("Malformed Option %s\n", opt_name); done = TRUE; } } opt_arg++; break; case '}': if (targ != -1) targ = -1; else if (instance != -1) instance = -1; opt_arg++; break; case ',': case '.': if (instance == -1) done = TRUE; else if (targ >= 0) targ++; else if (instance >= 0) instance++; opt_arg++; break; case '\0': done = TRUE; break; default: tok_end = end; for (i = 0; tok_list[i]; i++) { tok_end2 = strchr(opt_arg, tok_list[i]); if ((tok_end2) && (tok_end2 < tok_end)) tok_end = tok_end2; } callback(callback_arg, instance, targ, simple_strtol(opt_arg, NULL, 0)); opt_arg = tok_end; break; } } return (opt_arg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -