📄 ncr5380.c
字号:
char *lprint_opcode(int opcode, char *pos, char *buffer, int length);#ifndef NCR5380_proc_infostatic#endifint NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout){ 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 spin_lock_irq(&io_request_lock); 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); spin_unlock_irq(&io_request_lock); *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);}/** * NCR5380_init - initialise an NCR5380 * @instance: adapter to configure * @flags: control flags * * Initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. * * Locks: interrupts must be enabled when we are called */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; if(in_interrupt()) printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); /* * 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; } hostdata->time_expires = 0; hostdata->next_timer = NULL;#ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) printk(KERN_WARNING "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); } }}/** * NCR5380_queue_command - queue a command * @cmd: SCSI command * @done: completion handler * * 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. * * Locks: io_request lock held by caller. Called functions drop and * retake this lock. Called functions take dma lock. *//* 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 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; } dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); /* Run the coroutine if it isn't already running. */ run_main(); return 0;}/** * NCR5380_main - NCR state machines * * 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. * * Locks; The caller must hold the io_request_lock. The lock will still be * held on return but may be dropped while running. Called functions take * the DMA lock. */static void NCR5380_main(void) { Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; /* * 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. */ do { /* Lock held here */ done = 1; for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { hostdata = (struct NCR5380_hostdata *) instance->hostdata; /* Lock held here */ if (!hostdata->connected && !hostdata->selecting) { dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); /* * Search through the issue_queue for a command destined * for a target that's not busy. */ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) { if (prev != tmp) dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); /* 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; /* * 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. */ dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); /* * A successful selection is defined as one that * leaves us with the command connected and * in hostdata->connected, OR has terminated the * command. * * With successful commands, we fall through * and see if we can do an information transfer, * with failures we will restart. */ hostdata->selecting = 0; /* RvC: have to preset this to indicate a new command is being performed */ if (!NCR5380_select(instance, tmp, /* * REQUEST SENSE commands are issued without tagged * queueing, even on SCSI-II devices because the * contingent allegiance condition exists for the * entire unit. */ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { LIST(tmp, hostdata->issue_queue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -