📄 in2000.c
字号:
} } /* OK - find out which device reselected us. */ id = read_3393(hostdata,WD_SOURCE_ID); id &= SRCID_MASK; /* and extract the lun from the ID message. (Note that we don't * bother to check for a valid message here - I guess this is * not the right way to go, but....) */ lun = read_3393(hostdata,WD_DATA); if (hostdata->level2 < L2_RESELECT) write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK); lun &= 7; /* Now we look for the command that's reconnecting. */ cmd = (Scsi_Cmnd *)hostdata->disconnected_Q; patch = NULL; while (cmd) { if (id == cmd->target && lun == cmd->lun) break; patch = cmd; cmd = (Scsi_Cmnd *)cmd->host_scribble; } /* Hmm. Couldn't find a valid command.... What to do? */ if (!cmd) { printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun); break; } /* Ok, found the command - now start it up again. */ if (patch) patch->host_scribble = cmd->host_scribble; else hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble; hostdata->connected = cmd; /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' * because these things are preserved over a disconnect. * But we DO need to fix the DPD bit so it's correct for this command. */ if (is_dir_out(cmd)) write_3393(hostdata,WD_DESTINATION_ID,cmd->target); else write_3393(hostdata,WD_DESTINATION_ID,cmd->target | DSTID_DPD); if (hostdata->level2 >= L2_RESELECT) { write_3393_count(hostdata,0); /* we want a DATA_PHASE interrupt */ write_3393(hostdata,WD_COMMAND_PHASE, 0x45); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; } else hostdata->state = S_CONNECTED;DB(DB_INTR,printk("-%ld",cmd->pid)) break; default: printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs); } write1_io(0, IO_LED_OFF);DB(DB_INTR,printk("} "))/* release the SMP spin_lock and restore irq state */ CLISPIN_UNLOCK(flags);}#define RESET_CARD 0#define RESET_CARD_AND_BUS 1#define B_FLAG 0x80static int reset_hardware(struct Scsi_Host *instance, int type){struct IN2000_hostdata *hostdata;int qt,x;unsigned long flags; hostdata = (struct IN2000_hostdata *)instance->hostdata; write1_io(0, IO_LED_ON); if (type == RESET_CARD_AND_BUS) { write1_io(0,IO_CARD_RESET); x = read1_io(IO_HARDWARE); } x = read_3393(hostdata,WD_SCSI_STATUS); /* clear any WD intrpt */ write_3393(hostdata,WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8); write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF)); save_flags(flags); cli(); write1_io(0,IO_FIFO_WRITE); /* clear fifo counter */ write1_io(0,IO_FIFO_READ); /* start fifo out in read mode */ write_3393(hostdata,WD_COMMAND, WD_CMD_RESET); while (!(READ_AUX_STAT() & ASR_INT)) ; /* wait for RESET to complete */ x = read_3393(hostdata,WD_SCSI_STATUS); /* clear interrupt */ restore_flags(flags); write_3393(hostdata,WD_QUEUE_TAG,0xa5); /* any random number */ qt = read_3393(hostdata,WD_QUEUE_TAG); if (qt == 0xa5) { x |= B_FLAG; write_3393(hostdata,WD_QUEUE_TAG,0); } write_3393(hostdata,WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write1_io(0, IO_LED_OFF); return x;}int in2000_reset(Scsi_Cmnd *cmd, unsigned int reset_flags){unsigned long flags;struct Scsi_Host *instance;struct IN2000_hostdata *hostdata;int x; instance = cmd->host; hostdata = (struct IN2000_hostdata *)instance->hostdata; printk("scsi%d: Reset. ", instance->host_no); save_flags(flags); cli(); /* do scsi-reset here */ reset_hardware(instance, RESET_CARD_AND_BUS); for (x = 0; x < 8; x++) { hostdata->busy[x] = 0; hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */ } hostdata->input_Q = NULL; hostdata->selecting = NULL; hostdata->connected = NULL; hostdata->disconnected_Q = NULL; hostdata->state = S_UNCONNECTED; hostdata->fifo = FI_FIFO_UNUSED; hostdata->incoming_ptr = 0; hostdata->outgoing_len = 0; cmd->result = DID_RESET << 16; restore_flags(flags); return 0;}int in2000_abort (Scsi_Cmnd *cmd){struct Scsi_Host *instance;struct IN2000_hostdata *hostdata;Scsi_Cmnd *tmp, *prev;unsigned long flags;uchar sr, asr;unsigned long timeout; save_flags (flags); cli(); instance = cmd->host; hostdata = (struct IN2000_hostdata *)instance->hostdata; printk ("scsi%d: Abort-", instance->host_no); printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(),read_3393_count(hostdata),cmd->SCp.this_residual,cmd->SCp.buffers_residual, cmd->SCp.have_data_in,read1_io(IO_FIFO_COUNT));/* * Case 1 : If the command hasn't been issued yet, we simply remove it * from the inout_Q. */ tmp = (Scsi_Cmnd *)hostdata->input_Q; prev = 0; while (tmp) { if (tmp == cmd) { if (prev) prev->host_scribble = cmd->host_scribble; cmd->host_scribble = NULL; cmd->result = DID_ABORT << 16; printk("scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid); cmd->scsi_done(cmd); restore_flags(flags); return SCSI_ABORT_SUCCESS; } prev = tmp; tmp = (Scsi_Cmnd *)tmp->host_scribble; }/* * Case 2 : If the command is connected, we're going to fail the abort * and let the high level SCSI driver retry at a later time or * issue a reset. * * Timeouts, and therefore aborted commands, will be highly unlikely * and handling them cleanly in this situation would make the common * case of noresets less efficient, and would pollute our code. So, * we fail. */ if (hostdata->connected == cmd) { printk("scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid); printk("sending wd33c93 ABORT command - "); write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_3393_cmd(hostdata, WD_CMD_ABORT);/* Now we have to attempt to flush out the FIFO... */ printk("flushing fifo - "); timeout = 1000000; do { asr = READ_AUX_STAT(); if (asr & ASR_DBR) read_3393(hostdata, WD_DATA); } while (!(asr & ASR_INT) && timeout-- > 0); sr = read_3393(hostdata, WD_SCSI_STATUS); printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout); /* * Abort command processed. * Still connected. * We must disconnect. */ printk("sending wd33c93 DISCONNECT command - "); write_3393_cmd(hostdata, WD_CMD_DISCONNECT); timeout = 1000000; asr = READ_AUX_STAT(); while ((asr & ASR_CIP) && timeout-- > 0) asr = READ_AUX_STAT(); sr = read_3393(hostdata, WD_SCSI_STATUS); printk("asr=%02x, sr=%02x.",asr,sr); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; hostdata->state = S_UNCONNECTED; cmd->result = DID_ABORT << 16; cmd->scsi_done(cmd); in2000_execute (instance); restore_flags(flags); return SCSI_ABORT_SUCCESS; }/* * Case 3: If the command is currently disconnected from the bus, * we're not going to expend much effort here: Let's just return * an ABORT_SNOOZE and hope for the best... */ for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp; tmp=(Scsi_Cmnd *)tmp->host_scribble) if (cmd == tmp) { restore_flags(flags); printk("Sending ABORT_SNOOZE. "); return SCSI_ABORT_SNOOZE; }/* * Case 4 : If we reached this point, the command was not found in any of * the queues. * * We probably reached this point because of an unlikely race condition * between the command completing successfully and the abortion code, * so we won't panic, but we will notify the user in case something really * broke. */ in2000_execute (instance); restore_flags(flags); printk("scsi%d: warning : SCSI command probably completed successfully" " before abortion. ", instance->host_no); return SCSI_ABORT_NOT_RUNNING;}#define MAX_IN2000_HOSTS 3#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *))#define SETUP_BUFFER_SIZE 200static char setup_buffer[SETUP_BUFFER_SIZE];static char setup_used[MAX_SETUP_ARGS];static int done_setup = 0;void __init in2000_setup (char *str, int *ints){int i;char *p1,*p2; strncpy(setup_buffer,str,SETUP_BUFFER_SIZE); setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; p1 = setup_buffer; i = 0; while (*p1 && (i < MAX_SETUP_ARGS)) { p2 = strchr(p1, ','); if (p2) { *p2 = '\0'; if (p1 != p2) setup_args[i] = p1; p1 = p2 + 1; i++; } else { setup_args[i] = p1; break; } } for (i=0; i<MAX_SETUP_ARGS; i++) setup_used[i] = 0; done_setup = 1;}/* check_setup_args() returns index if key found, 0 if not */static int __init check_setup_args(char *key, int *flags, int *val, char *buf){int x;char *cp; for (x=0; x<MAX_SETUP_ARGS; x++) { if (setup_used[x]) continue; if (!strncmp(setup_args[x], key, strlen(key))) break; } if (x == MAX_SETUP_ARGS) return 0; setup_used[x] = 1; cp = setup_args[x] + strlen(key); *val = -1; if (*cp != ':') return ++x; cp++; if ((*cp >= '0') && (*cp <= '9')) { *val = simple_strtoul(cp,NULL,0); } return ++x;}/* The "correct" (ie portable) way to access memory-mapped hardware * such as the IN2000 EPROM and dip switch is through the use of * special macros declared in 'asm/io.h'. We use readb() and readl() * when reading from the card's BIOS area in in2000_detect(). */static const unsigned int *bios_tab[] in2000__INITDATA = { (unsigned int *)0xc8000, (unsigned int *)0xd0000, (unsigned int *)0xd8000, 0 };static const unsigned short base_tab[] in2000__INITDATA =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -