📄 ncr5380.c
字号:
data = NCR5380_read(CURRENT_SCSI_DATA_REG); status = NCR5380_read(STATUS_REG); mr = NCR5380_read(MODE_REG); icr = NCR5380_read(INITIATOR_COMMAND_REG); basr = NCR5380_read(BUS_AND_STATUS_REG); restore_flags(flags); printk("STATUS_REG: %02x ", status); for (i = 0; signals[i].mask; ++i) if (status & signals[i].mask) printk(",%s", signals[i].name); printk("\nBASR: %02x ", basr); for (i = 0; basrs[i].mask; ++i) if (basr & basrs[i].mask) printk(",%s", basrs[i].name); printk("\nICR: %02x ", icr); for (i = 0; icrs[i].mask; ++i) if (icr & icrs[i].mask) printk(",%s", icrs[i].name); printk("\nMODE: %02x ", mr); for (i = 0; mrs[i].mask; ++i) if (mr & mrs[i].mask) printk(",%s", mrs[i].name); printk("\n");}static struct { unsigned char value; const char *name;} phases[] = { {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, {PHASE_UNKNOWN, "UNKNOWN"}};/* * NCR5380_print_phase - show SCSI phase * @instance: adapter to dump * * Print the current SCSI phase for debugging purposes * * Locks: none */static void NCR5380_print_phase(struct Scsi_Host *instance){ NCR5380_local_declare(); unsigned char status; int i; NCR5380_setup(instance); status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no); else { for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); }}#endif/* * We need to have our coroutine active given these constraints : * 1. The mutex flag, main_running, can only be set when the main * routine can actually process data, otherwise SCSI commands * will never get issued. * * 2. NCR5380_main() shouldn't be called before it has exited, because * other drivers have had kernel stack overflows in similar * situations. * * 3. We don't want to inline NCR5380_main() because of space concerns, * even though it is only called in two places. * * So, the solution is to set the mutex in an inline wrapper for the * main coroutine, and have the main coroutine exit with interrupts * disabled after the final search through the queues so that no race * conditions are possible. */static unsigned long main_running = 0;/* * Function : run_main(void) * * Purpose : insure that the coroutine is running and will process our * request. main_running is checked/set here (in an inline function) * rather than in NCR5380_main itself to reduce the chances of stack * overflow. * */static __inline__ void run_main(void){ if (!test_and_set_bit(0, &main_running)) NCR5380_main();}/* * These need tweaking, and would probably work best as per-device * flags initialized differently for disk, tape, cd, etc devices. * People with broken devices are free to experiment as to what gives * the best results for them. * * USLEEP_SLEEP should be a minimum seek time. * * USLEEP_POLL should be a maximum rotational latency. */#ifndef USLEEP_SLEEP/* 20 ms (reasonable hard disk speed) */#define USLEEP_SLEEP (20*HZ/1000)#endif/* 300 RPM (floppy speed) */#ifndef USLEEP_POLL#define USLEEP_POLL (200*HZ/1000)#endif#ifndef USLEEP_WAITLONG/* RvC: (reasonable time to wait on select error) */#define USLEEP_WAITLONG USLEEP_SLEEP#endifstatic struct Scsi_Host *expires_first = NULL;/* * Function : int should_disconnect (unsigned char cmd) * * Purpose : decide weather a command would normally disconnect or * not, since if it won't disconnect we should go to sleep. * * Input : cmd - opcode of SCSI command * * Returns : DISCONNECT_LONG if we should disconnect for a really long * time (ie always, sleep, look for REQ active, sleep), * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal * time-to-data delay, DISCONNECT_NONE if this command would return * immediately. * * Future sleep algorithms based on time to data can exploit * something like this so they can differentiate between "normal" * (ie, read, write, seek) and unusual commands (ie, * format). * * Note : We don't deal with commands that handle an immediate disconnect, * */static int should_disconnect(unsigned char cmd){ switch (cmd) { case READ_6: case WRITE_6: case SEEK_6: case READ_10: case WRITE_10: case SEEK_10: return DISCONNECT_TIME_TO_DATA; case FORMAT_UNIT: case SEARCH_HIGH: case SEARCH_LOW: case SEARCH_EQUAL: return DISCONNECT_LONG; default: return DISCONNECT_NONE; }}/* * Assumes instance->time_expires has been set in higher level code. * * Locks: Caller must hold io_request_lock */static int NCR5380_set_timer(struct Scsi_Host *instance){ struct Scsi_Host *tmp, **prev; if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { return -1; } for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) if (((struct NCR5380_hostdata *) instance->hostdata)->time_expires < ((struct NCR5380_hostdata *) tmp->hostdata)->time_expires) break; ((struct NCR5380_hostdata *) instance->hostdata)->next_timer = tmp; *prev = instance; mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); return 0;}/** * NCR5380_timer_fn - handle polled timeouts * @unused: unused * * Walk the list of controllers, find which controllers have exceeded * their expiry timeout and then schedule the processing co-routine to * do the real work. * * Doing something about unwanted reentrancy here might be useful * * Locks: disables irqs, takes and frees io_request_lock */ static void NCR5380_timer_fn(unsigned long unused){ struct Scsi_Host *instance; spin_lock_irq(&io_request_lock); for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires = 0; expires_first = instance; } del_timer(&usleep_timer); if (expires_first) { usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; add_timer(&usleep_timer); } run_main(); spin_unlock_irq(&io_request_lock);}/** * NCR5380_all_init - global setup * * Set up the global values and timers needed by the NCR5380 driver */ static inline void NCR5380_all_init(void){ static int done = 0; if (!done) { dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); done = 1; init_timer(&usleep_timer); usleep_timer.function = NCR5380_timer_fn; }}static int probe_irq __initdata = 0;/** * probe_intr - helper for IRQ autoprobe * @irq: interrupt number * @dev_id: unused * @regs: unused * * Set a flag to indicate the IRQ in question was received. This is * used by the IRQ probe code. */ static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs){ probe_irq = irq;}/** * NCR5380_probe_irq - find the IRQ of an NCR5380 * @instance: NCR5380 controller * @possible: bitmask of ISA IRQ lines * * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ * and then looking to see what interrupt actually turned up. * * Locks: none, irqs must be enabled on entry */static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible){ NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned long timeout; int trying_irqs, i, mask; NCR5380_setup(instance); for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0)) trying_irqs |= mask; timeout = jiffies + (250 * HZ / 1000); probe_irq = IRQ_NONE; /* * A interrupt is triggered whenever BSY = false, SEL = true * and a bit set in the SELECT_ENABLE_REG is asserted on the * SCSI bus. * * Note that the bus is only driven when the phase control signals * (I/O, C/D, and MSG) match those in the TCR, so we must reset that * to zero. */ NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); while (probe_irq == IRQ_NONE && time_before(jiffies, timeout)) barrier(); NCR5380_write(SELECT_ENABLE_REG, 0); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) if (trying_irqs & mask) free_irq(i, NULL); return probe_irq;}/** * NCR58380_print_options - show options * @instance: unused for now * * Called by probe code indicating the NCR5380 driver options that * were selected. At some point this will switch to runtime options * read from the adapter in question * * Locks: none */static void __init NCR5380_print_options(struct Scsi_Host *instance){ printk(" generic options"#ifdef AUTOPROBE_IRQ " AUTOPROBE_IRQ"#endif#ifdef AUTOSENSE " AUTOSENSE"#endif#ifdef DIFFERENTIAL " DIFFERENTIAL"#endif#ifdef REAL_DMA " REAL DMA"#endif#ifdef REAL_DMA_POLL " REAL DMA POLL"#endif#ifdef PARITY " PARITY"#endif#ifdef PSEUDO_DMA " PSEUDO DMA"#endif#ifdef UNSAFE " UNSAFE "#endif ); printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); }}/** * NCR5380_print_status - dump controller info * @instance: controller to dump * * Print commands in the various queues, called from NCR5380_abort * and NCR5380_debug to aid debugging. * * Locks: called functions disable irqs, missing queue lock in proc call */static void NCR5380_print_status(struct Scsi_Host *instance){ static char pr_bfr[512]; char *start; int len; printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); NCR5380_dprint(NDEBUG_ANY, instance); NCR5380_dprint_phase(NDEBUG_ANY, instance); len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr);}/******************************************//* * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] * * *buffer: I/O buffer * **start: if inout == FALSE pointer into buffer where user read should start * offset: current offset * length: length of buffer * hostno: Scsi_Host host_no * inout: TRUE - user is writing; FALSE - user is reading * * Return the number of bytes read from or written */#undef SPRINTF#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)staticchar *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length);staticchar *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len);static
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -