📄 fas216.c
字号:
SCpnt->result = DID_ERROR << 16; done(SCpnt); } save_flags_cli(flags); if (!info->SCpnt || info->scsi.disconnectable) fas216_kick(info); restore_flags(flags); } else { /* no interrupts to rely on - we'll have to handle the * command ourselves. For now, we give up. */ SCpnt->result = DID_ERROR << 16; done(SCpnt); } return 0;}/* Function: void fas216_internal_done(Scsi_Cmnd *SCpnt) * Purpose : trigger restart of a waiting thread in fas216_command * Params : SCpnt - Command to wake */static void fas216_internal_done(Scsi_Cmnd *SCpnt){ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; fas216_checkmagic(info, "fas216_internal_done"); info->internal_done = 1;}/* Function: int fas216_command(Scsi_Cmnd *SCpnt) * Purpose : queue a command for adapter to process. * Params : SCpnt - Command to queue * Returns : scsi result code */int fas216_command(Scsi_Cmnd *SCpnt){ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; unsigned long flags; fas216_checkmagic(info, "fas216_command"); info->internal_done = 0; fas216_queue_command(SCpnt, fas216_internal_done); /* * This wastes time, since we can't return until the command is * complete. We can't seep either since we may get re-entered! * However, we must re-enable interrupts, or else we'll be * waiting forever. */ save_flags(flags); sti(); while (!info->internal_done) barrier(); restore_flags(flags); return SCpnt->result;}/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1, * Scsi_Cmnd **SCpntp2, int result) * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 * Params : SCpntp1 - pointer to command to return * SCpntp2 - pointer to command to check * result - result to pass back to mid-level done function * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command * structure as *SCpntp2. */static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result){ Scsi_Cmnd *SCpnt = *SCpntp1; if (SCpnt) { *SCpntp1 = NULL; SCpnt->result = result; SCpnt->scsi_done(SCpnt); } if (SCpnt == *SCpntp2) *SCpntp2 = NULL;}/* Function: int fas216_abort(Scsi_Cmnd *SCpnt) * Purpose : abort a command if something horrible happens. * Params : SCpnt - Command that is believed to be causing a problem. * Returns : one of SCSI_ABORT_ macros. */int fas216_abort(Scsi_Cmnd *SCpnt){ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; int result = SCSI_ABORT_SNOOZE; fas216_checkmagic(info, "fas216_abort"); info->stats.aborts += 1; print_debug_list(); fas216_dumpstate(info); fas216_dumpinfo(info); printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no); do { /* If command is waiting in the issue queue, then we can * simply remove the command and return abort status */ if (queue_removecmd(&info->queues.issue, SCpnt)) { SCpnt->result = DID_ABORT << 16; SCpnt->scsi_done(SCpnt); printk("command on issue queue"); result = SCSI_ABORT_SUCCESS; break; } /* If the command is on the disconencted queue, we need to * reconnect to the device */ if (queue_cmdonqueue(&info->queues.disconnected, SCpnt)) printk("command on disconnected queue"); /* If the command is connected, we need to flag that the * command needs to be aborted */ if (info->SCpnt == SCpnt) printk("command executing"); /* If the command is pending for execution, then again * this is simple - we remove it and report abort status */ if (info->origSCpnt == SCpnt) { info->origSCpnt = NULL; SCpnt->result = DID_ABORT << 16; SCpnt->scsi_done(SCpnt); printk("command waiting for execution"); result = SCSI_ABORT_SUCCESS; break; } } while (0); printk("\n"); return result;}/* Function: void fas216_reset_state(FAS216_Info *info) * Purpose : Initialise driver internal state * Params : info - state to initialise */static void fas216_reset_state(FAS216_Info *info){ neg_t sync_state, wide_state; int i; fas216_checkmagic(info, "fas216_reset_state"); /* * Clear out all stale info in our state structure */ memset(info->busyluns, 0, sizeof(info->busyluns)); msgqueue_flush(&info->scsi.msgs); info->scsi.reconnected.target = 0; info->scsi.reconnected.lun = 0; info->scsi.reconnected.tag = 0; info->scsi.disconnectable = 0; info->scsi.aborting = 0; info->scsi.phase = PHASE_IDLE; info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); if (info->ifcfg.wide_max_size == 0) wide_state = neg_invalid; else#ifdef SCSI2_WIDE wide_state = neg_wait;#else wide_state = neg_invalid;#endif if (info->host->dma_channel == NO_DMA || !info->dma.setup) sync_state = neg_invalid; else#ifdef SCSI2_SYNC sync_state = neg_wait;#else sync_state = neg_invalid;#endif for (i = 0; i < 8; i++) { info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; info->device[i].sync_state = sync_state; info->device[i].wide_state = wide_state; info->device[i].period = info->ifcfg.asyncperiod / 4; info->device[i].stp = info->scsi.async_stp; info->device[i].sof = 0; info->device[i].wide_xfer = 0; }}/* Function: void fas216_init_chip(FAS216_Info *info) * Purpose : Initialise FAS216 state after reset * Params : info - state structure for interface */static void fas216_init_chip(FAS216_Info *info){ fas216_checkmagic(info, "fas216_init_chip"); outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info)); outb(info->scsi.cfg[0], REG_CNTL1(info)); outb(info->scsi.cfg[1], REG_CNTL2(info)); outb(info->scsi.cfg[2], REG_CNTL3(info)); outb(info->ifcfg.select_timeout, REG_STIM(info)); outb(0, REG_SOF(info)); outb(info->scsi.async_stp, REG_STP(info)); outb(info->scsi.cfg[0], REG_CNTL1(info));}/* Function: int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Purpose : resets the adapter if something horrible happens. * Params : SCpnt - Command that is believed to be causing a problem. * reset_flags - flags indicating reset type that is believed * to be required. * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET * macros. */int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags){ FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; Scsi_Cmnd *SCptr; int result = 0; fas216_checkmagic(info, "fas216_reset"); /* * Validate that command is actually on one of our queues if we're doing * an asynchronous reset */ if (reset_flags & SCSI_RESET_ASYNCHRONOUS && SCpnt && info->SCpnt != SCpnt && info->origSCpnt != SCpnt && !queue_cmdonqueue(&info->queues.disconnected, SCpnt) && !queue_cmdonqueue(&info->queues.issue, SCpnt)) { printk("scsi%d: fas216_reset: asynchronous reset for unknown command\n", info->host->host_no); return SCSI_RESET_NOT_RUNNING; } info->stats.resets += 1; print_debug_list(); printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no); if (SCpnt) printk(" for target %d ", SCpnt->target); outb(info->scsi.cfg[3], REG_CNTL3(info)); fas216_stoptransfer(info); switch (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) { case SCSI_RESET_SUGGEST_BUS_RESET: outb(CMD_RESETSCSI, REG_CMD(info)); outb(CMD_NOP, REG_CMD(info)); result |= SCSI_RESET_BUS_RESET; break; case SCSI_RESET_SUGGEST_HOST_RESET: outb(CMD_RESETCHIP, REG_CMD(info)); outb(CMD_NOP, REG_CMD(info)); result |= SCSI_RESET_HOST_RESET; break; default: outb(CMD_RESETCHIP, REG_CMD(info)); outb(CMD_NOP, REG_CMD(info)); outb(CMD_RESETSCSI, REG_CMD(info)); result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET; break; } udelay(300); fas216_reset_state(info); fas216_init_chip(info); /* * Signal all commands in progress have been reset */ fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16); while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL) fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16); if (SCpnt) { /* * Command not found on disconnected queue, nor currently * executing command - check pending commands */ if (info->origSCpnt == SCpnt) info->origSCpnt = NULL; queue_removecmd(&info->queues.issue, SCpnt); SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); } printk("\n"); return result | SCSI_RESET_SUCCESS;}/* Function: int fas216_init(struct Scsi_Host *instance) * Purpose : initialise FAS/NCR/AMD SCSI ic. * Params : instance - a driver-specific filled-out structure * Returns : 0 on success */int fas216_init(struct Scsi_Host *instance){ FAS216_Info *info = (FAS216_Info *)instance->hostdata; unsigned long flags; int target_jiffies; info->magic_start = MAGIC; info->magic_end = MAGIC; info->host = instance; info->scsi.cfg[0] = instance->this_id; info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB; info->scsi.type = "unknown"; info->SCpnt = NULL; fas216_reset_state(info); memset(&info->stats, 0, sizeof(info->stats)); msgqueue_initialise(&info->scsi.msgs); if (!queue_initialise(&info->queues.issue)) return 1; if (!queue_initialise(&info->queues.disconnected)) { queue_free(&info->queues.issue); return 1; } outb(0, REG_CNTL3(info)); outb(CNTL2_S2FE, REG_CNTL2(info)); if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) { info->scsi.type = "NCR53C90"; } else { outb(0, REG_CNTL2(info)); outb(0, REG_CNTL3(info)); outb(5, REG_CNTL3(info)); if (inb(REG_CNTL3(info)) != 5) { info->scsi.type = "NCR53C90A"; } else { outb(0, REG_CNTL3(info)); info->scsi.type = "NCR53C9x"; } } outb(CNTL3_ADIDCHK, REG_CNTL3(info)); outb(0, REG_CNTL3(info)); outb(CMD_RESETCHIP, REG_CMD(info)); outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info)); outb(CNTL2_ENF, REG_CNTL2(info)); outb(CMD_RESETCHIP, REG_CMD(info)); switch (inb(REG1_ID(info))) { case 12: info->scsi.type = "Am53CF94"; break; default: break; } udelay(300); /* now for the real initialisation */ fas216_init_chip(info); outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info)); outb(CMD_RESETSCSI, REG_CMD(info)); /* scsi standard says 250ms */ target_jiffies = jiffies + (25 * HZ) / 100; save_flags(flags); sti(); while (jiffies < target_jiffies) barrier(); restore_flags(flags); outb(info->scsi.cfg[0], REG_CNTL1(info)); inb(REG_INST(info)); /* now for the real initialisation */ fas216_init_chip(info); fas216_checkmagic(info, "fas216_init"); return 0;}/* Function: int fas216_release(struct Scsi_Host *instance) * Purpose : release all resources and put everything to bed for * FAS/NCR/AMD SCSI ic. * Params : instance - a driver-specific filled-out structure * Returns : 0 on success */int fas216_release(struct Scsi_Host *instance){ FAS216_Info *info = (FAS216_Info *)instance->hostdata; fas216_checkmagic(info, "fas216_release"); outb(CMD_RESETCHIP, REG_CMD(info)); queue_free(&info->queues.disconnected); queue_free(&info->queues.issue); return 0;}int fas216_print_stats(FAS216_Info *info, char *buffer){ return sprintf(buffer, "Queued commands: %-10u Issued commands: %-10u\n" "Done commands : %-10u Reads : %-10u\n" "Writes : %-10u Others : %-10u\n" "Disconnects : %-10u Aborts : %-10u\n" "Resets : %-10u\n", info->stats.queues, info->stats.removes, info->stats.fins, info->stats.reads, info->stats.writes, info->stats.miscs, info->stats.disconnects, info->stats.aborts, info->stats.resets);}int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer){ struct fas216_device *dev = &info->device[scd->id]; int len = 0; char *p; proc_print_scsidevice(scd, buffer, &len, 0); p = buffer + len; p += sprintf(p, " Extensions: "); if (scd->tagged_supported) p += sprintf(p, "TAG %sabled [%d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -