📄 ncr5380.c
字号:
int length, int hostno, int inout){ unsigned long flags; char *pos = buffer; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; for (instance = first_instance; instance && instance->host_no != hostno; instance = instance->next); if (!instance) return (-ESRCH); hostdata = (struct NCR5380_hostdata *) instance->hostdata; if (inout) { /* Has data been written to the file ? */#ifdef DTC_PUBLIC_RELEASE dtc_wmaxi = dtc_maxi = 0;#endif#ifdef PAS16_PUBLIC_RELEASE pas_wmaxi = pas_maxi = 0;#endif return (-ENOSYS); /* Currently this is a no-op */ } SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE);#ifdef DTC_PUBLIC_RELEASE SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);#endif#ifdef T128_PUBLIC_RELEASE SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);#endif#ifdef GENERIC_NCR5380_PUBLIC_RELEASE SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);#endif#ifdef PAS16_PUBLIC_RELEASE SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);#endif SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base); SPRINTF("io_port: %04x ", (int) instance->io_port); if (instance->irq == IRQ_NONE) SPRINTF("IRQ: None.\n"); else SPRINTF("IRQ: %d.\n", instance->irq);#ifdef DTC_PUBLIC_RELEASE SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi);#endif#ifdef PAS16_PUBLIC_RELEASE SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi);#endif save_flags(flags); cli(); SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); else pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length); SPRINTF("scsi%d: issue_queue\n", instance->host_no); for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); restore_flags(flags); *start = buffer; if (pos - buffer < offset) return 0; else if (pos - buffer - offset < length) return pos - buffer - offset; return length;}staticchar *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length){ SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->host->host_no, cmd->target, cmd->lun); SPRINTF(" command = "); pos = lprint_command(cmd->cmnd, pos, buffer, length); return (pos);}staticchar *lprint_command(unsigned char *command, char *pos, char *buffer, int length){ int i, s; pos = lprint_opcode(command[0], pos, buffer, length); for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) SPRINTF("%02x ", command[i]); SPRINTF("\n"); return (pos);}staticchar *lprint_opcode(int opcode, char *pos, char *buffer, int length){ SPRINTF("%2d (0x%02x)", opcode, opcode); return (pos);}/* * Function : void NCR5380_init (struct Scsi_Host *instance, flags) * * Purpose : initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * * Inputs : instance - instantiation of the 5380 driver. * * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. * */static void __init NCR5380_init(struct Scsi_Host *instance, int flags){ NCR5380_local_declare(); int i, pass; unsigned long timeout; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; /* * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. */#ifdef NCR53C400 if (flags & FLAG_NCR53C400) instance->NCR5380_instance_name += NCR53C400_address_adjust;#endif NCR5380_setup(instance); NCR5380_all_init(); hostdata->aborted = 0; hostdata->id_mask = 1 << instance->this_id; for (i = hostdata->id_mask; i <= 0x80; i <<= 1) if (i > hostdata->id_mask) hostdata->id_higher_mask |= i; for (i = 0; i < 8; ++i) hostdata->busy[i] = 0;#ifdef REAL_DMA hostdata->dmalen = 0;#endif hostdata->targets_present = 0; hostdata->connected = NULL; hostdata->issue_queue = NULL; hostdata->disconnected_queue = NULL;#ifdef NCR5380_STATS for (i = 0; i < 8; ++i) { hostdata->time_read[i] = 0; hostdata->time_write[i] = 0; hostdata->bytes_read[i] = 0; hostdata->bytes_write[i] = 0; } hostdata->timebase = 0; hostdata->pendingw = 0; hostdata->pendingr = 0;#endif /* The CHECK code seems to break the 53C400. Will check it later maybe */ if (flags & FLAG_NCR53C400) hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags; else hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; if (!the_template) { the_template = instance->hostt; first_instance = instance; }#ifdef USLEEP hostdata->time_expires = 0; hostdata->next_timer = NULL;#endif#ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) ) printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" " be incorrectly cleared.\n", instance->host_no);#endif /* def AUTOSENSE */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0);#ifdef NCR53C400 if (hostdata->flags & FLAG_NCR53C400) { NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); }#endif /* * Detect and correct bus wedge problems. * * If the system crashed, it may have crashed in a state * where a SCSI command was still executing, and the * SCSI bus is not in a BUS FREE STATE. * * If this is the case, we'll try to abort the currently * established nexus which we know nothing about, and that * failing, do a hard reset of the SCSI bus */ for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { switch (pass) { case 1: case 3: case 5: printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); timeout = jiffies + 5 * HZ; while (time_before(jiffies,timeout) && (NCR5380_read(STATUS_REG) & SR_BSY)); break; case 2: printk("scsi%d: bus busy, attempting abort\n", instance->host_no); do_abort(instance); break; case 4: printk("scsi%d: bus busy, attempting reset\n", instance->host_no); do_reset(instance); break; case 6: printk("scsi%d: bus locked solid or invalid override\n", instance->host_no); } }}/* * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with * a pointer to the command descriptor. * * Returns : 0 * * Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * *//* Only make static if a wrapper function is used */#ifndef NCR5380_queue_commandstatic#endifint NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { struct Scsi_Host *instance = cmd->host; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp;#if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { case WRITE_6: case WRITE_10: printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no); cmd->result = (DID_ERROR << 16); done(cmd); return 0; }#endif /* (NDEBUG & NDEBUG_NO_WRITE) */#ifdef NCR5380_STATS#if 0 if (!hostdata->connected && !hostdata->issue_queue && !hostdata->disconnected_queue) { hostdata->timebase = jiffies; }#endif#ifdef NCR5380_STAT_LIMIT if (cmd->request_bufflen > NCR5380_STAT_LIMIT)#endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_write[cmd->target] += cmd->request_bufflen; hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); hostdata->bytes_read[cmd->target] += cmd->request_bufflen; hostdata->pendingr++; break; }#endif /* * We use the host_scribble field as a pointer to the next command * in a queue */ cmd->host_scribble = NULL; cmd->scsi_done = done; cmd->result = 0; /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will * clear the contingent allegiance condition that exists and the * sense data is only guaranteed to be valid while the condition exists. */ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = cmd; } else { for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; }#if (NDEBUG & NDEBUG_QUEUES) printk("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");#endif/* Run the coroutine if it isn't already running. */ run_main(); return 0;}/* * Function : NCR5380_main (void) * * Purpose : NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. * * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. */static void NCR5380_main(void) { Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of * the host adapters have anything that can be done, at which point * we set main_running to 0 and exit. * * Interrupts are enabled before doing various other internal * instructions, after we've decided that we need to run through * the loop again. * * this should prevent any race conditions. */ spin_unlock_irq(&io_request_lock); save_flags(flags); do { cli(); /* Freeze request queues */ done = 1; for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { hostdata = (struct NCR5380_hostdata *) instance->hostdata; cli();#ifdef USLEEP if (!hostdata->connected && !hostdata->selecting) {#else if (!hostdata->connected) {#endif #if (NDEBUG & NDEBUG_MAIN) printk("scsi%d : not connected\n", instance->host_no);#endif /* * Search through the issue_queue for a command destined * for a target that's not busy. */#if (NDEBUG & NDEBUG_LISTS) for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); /*printk("%p ", tmp); */ if ((tmp == prev) && tmp) printk(" LOOP\n"); /* else printk("\n"); */#endif for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) {#if (NDEBUG & NDEBUG_LISTS) if (prev != tmp) printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun);#endif /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); prev->host_scribble = tmp->host_scribble; } else { REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; } tmp->host_scribble = NULL; /* reenable interrupts after finding one */ restore_flags(flags); /* * Attempt to establish an I_T_L nexus here. * On success, instance->hostdata->connected is set. * On failure, we must add the command back to the * issue queue so we can keep trying. */#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -