📄 ncr5380.c
字号:
#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_RELEASESPRINTF("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 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); sti(); *start=buffer; if (pos - buffer < offset) return 0; else if (pos - buffer - offset < length) return pos - buffer - offset; return length;}static char *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);}static char *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);}static char *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 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 (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. */ cli(); 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; /* * 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 { 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(); if (!hostdata->connected) {#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 */ sti(); /* * 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 /* * A successful selection is defined as one that * leaves us with the command connected and * in hostdata->connected, OR has terminated the * command.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -