📄 aic7xxx.c
字号:
AHC_AIC7770_FE = AHC_FENONE, AHC_AIC7850_FE = AHC_SPIOCAP, AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, AHC_AIC7870_FE = AHC_FENONE, AHC_AIC7880_FE = AHC_ULTRA, AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2| AHC_QUEUE_REGS|AHC_SG_PRELOAD, AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, AHC_AIC7896_FE = AHC_AIC7890_FE, AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA160, AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA160,} ahc_feature;struct aic7xxx_scb { struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ struct aic7xxx_scb *q_next; /* next scb in queue */ volatile scb_flag_type flags; /* current state of scb */ struct hw_scatterlist *sg_list; /* SG list in adapter format */ unsigned char tag_action; unsigned char sg_count; unsigned char sense_cmd[6]; /* * Allocate 6 characters for * sense command. */ unsigned int sg_length; /* We init this during buildscb so we * don't have to calculate anything * during underflow/overflow/stat code */ void *kmalloc_ptr;};/* * Define a linked list of SCBs. */typedef struct { struct aic7xxx_scb *head; struct aic7xxx_scb *tail;} scb_queue_type;static struct { unsigned char errno; const char *errmesg;} hard_error[] = { { ILLHADDR, "Illegal Host Access" }, { ILLSADDR, "Illegal Sequencer Address referenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, { SQPARERR, "Sequencer Ram Parity Error" }, { DPARERR, "Data-Path Ram Parity Error" }, { MPARERR, "Scratch Ram/SCB Array Ram Parity Error" }, { PCIERRSTAT,"PCI Error detected" }, { CIOPARERR, "CIOBUS Parity Error" }};static unsigned chargeneric_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };typedef struct { scb_queue_type free_scbs; /* * SCBs assigned to free slot on * card (no paging required) */ struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; struct aic7xxx_hwscb *hscbs; unsigned char numscbs; /* current number of scbs */ unsigned char maxhscbs; /* hardware scbs */ unsigned char maxscbs; /* max scbs including pageable scbs */ void *hscb_kmalloc_ptr;} scb_data_type;struct target_cmd { unsigned char mesg_bytes[4]; unsigned char command[28];};#define AHC_TRANS_CUR 0x0001#define AHC_TRANS_ACTIVE 0x0002#define AHC_TRANS_GOAL 0x0004#define AHC_TRANS_USER 0x0008#define AHC_TRANS_QUITE 0x0010typedef struct { unsigned char cur_width; unsigned char goal_width; unsigned char cur_period; unsigned char goal_period; unsigned char cur_offset; unsigned char goal_offset; unsigned char user_width; unsigned char user_period; unsigned char user_offset;} transinfo_type;/* * Define a structure used for each host adapter. Note, in order to avoid * problems with architectures I can't test on (because I don't have one, * such as the Alpha based systems) which happen to give faults for * non-aligned memory accesses, care was taken to align this structure * in a way that gauranteed all accesses larger than 8 bits were aligned * on the appropriate boundary. It's also organized to try and be more * cache line efficient. Be careful when changing this lest you might hurt * overall performance and bring down the wrath of the masses. */struct aic7xxx_host { /* * This is the first 64 bytes in the host struct */ /* * We are grouping things here....first, items that get either read or * written with nearly every interrupt */ volatile ahc_flag_type flags; ahc_feature features; /* chip features */ unsigned long base; /* card base address */ volatile unsigned char *maddr; /* memory mapped address */ unsigned long isr_count; /* Interrupt count */ unsigned long spurious_int; scb_data_type *scb_data; volatile unsigned short needsdtr; volatile unsigned short sdtr_pending; volatile unsigned short needwdtr; volatile unsigned short wdtr_pending; struct aic7xxx_cmd_queue { Scsi_Cmnd *head; Scsi_Cmnd *tail; } completeq; /* * Things read/written on nearly every entry into aic7xxx_queue() */ volatile scb_queue_type waiting_scbs; unsigned short discenable; /* Targets allowed to disconnect */ unsigned short tagenable; /* Targets using tagged I/O */ unsigned short orderedtag; /* Ordered Q tags allowed */ unsigned char unpause; /* unpause value for HCNTRL */ unsigned char pause; /* pause value for HCNTRL */ volatile unsigned char qoutfifonext; volatile unsigned char activescbs; /* active scbs */ volatile unsigned char max_activescbs; volatile unsigned char qinfifonext;#define DEVICE_PRESENT 0x01#define BUS_DEVICE_RESET_PENDING 0x02#define DEVICE_RESET_DELAY 0x04#define DEVICE_PRINT_SDTR 0x08#define DEVICE_PRINT_WDTR 0x10#define DEVICE_WAS_BUSY 0x20#define DEVICE_SCANNED 0x80 volatile unsigned char dev_flags[MAX_TARGETS]; volatile unsigned char dev_active_cmds[MAX_TARGETS]; volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; unsigned char dev_commands_sent[MAX_TARGETS]; unsigned int dev_timer_active; /* Which devs have a timer set */ struct timer_list dev_timer; unsigned long dev_expires[MAX_TARGETS];#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) spinlock_t spin_lock; volatile unsigned char cpu_lock_count[NR_CPUS];#endif#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS Scsi_Cmnd *dev_wdtr_cmnd[MAX_TARGETS]; Scsi_Cmnd *dev_sdtr_cmnd[MAX_TARGETS];#endif unsigned char dev_last_queue_full[MAX_TARGETS]; unsigned char dev_last_queue_full_count[MAX_TARGETS]; unsigned char dev_max_queue_depth[MAX_TARGETS]; volatile scb_queue_type delayed_scbs[MAX_TARGETS]; unsigned char msg_buf[9]; /* The message for the target */ unsigned char msg_type;#define MSG_TYPE_NONE 0x00#define MSG_TYPE_INITIATOR_MSGOUT 0x01#define MSG_TYPE_INITIATOR_MSGIN 0x02 unsigned char msg_len; /* Length of message */ unsigned char msg_index; /* Index into msg_buf array */ transinfo_type transinfo[MAX_TARGETS]; /* * We put the less frequently used host structure items after the more * frequently used items to try and ease the burden on the cache subsystem. * These entries are not *commonly* accessed, whereas the preceding entries * are accessed very often. The only exceptions are the qinfifo, qoutfifo, * and untagged_scbs array. But, they are often accessed only once and each * access into these arrays is likely to blow a cache line, so they are put * down here so we can minimize the number of cache lines required to hold * the preceeding entries. */ volatile unsigned char untagged_scbs[256]; volatile unsigned char qoutfifo[256]; volatile unsigned char qinfifo[256]; unsigned int irq; /* IRQ for this adapter */ int instance; /* aic7xxx instance number */ int scsi_id; /* host adapter SCSI ID */ int scsi_id_b; /* channel B for twin adapters */ unsigned int bios_address; int board_name_index; unsigned short needsdtr_copy; /* default config */ unsigned short needwdtr_copy; /* default config */ unsigned short ultraenb; /* Ultra mode target list */ unsigned short bios_control; /* bios control - SEEPROM */ unsigned short adapter_control; /* adapter control - SEEPROM */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) struct pci_dev *pdev;#endif unsigned char pci_bus; unsigned char pci_device_fn; struct seeprom_config sc; unsigned short sc_type; unsigned short sc_size; struct aic7xxx_host *next; /* allow for multiple IRQs */ struct Scsi_Host *host; /* pointer to scsi host */ int host_no; /* SCSI host number */ unsigned long mbase; /* I/O memory address */ ahc_chip chip; /* chip type */ /* * Statistics Kept: * * Total Xfers (count for each command that has a data xfer), * broken down further by reads && writes. * * Binned sizes, writes && reads: * < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K * * Total amounts read/written above 512 bytes (amts under ignored) * * NOTE: Enabling this feature is likely to cause a noticeable performance * decrease as the accesses into the stats structures blows apart multiple * cache lines and is CPU time consuming. * * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM * and blows apart all sorts of cache lines, I modified this so that we * no longer look at the LUN. All LUNs now go into the same bin on each * device for stats purposes. */ struct aic7xxx_xferstats { long w_total; /* total writes */ long r_total; /* total reads */#ifdef AIC7XXX_PROC_STATS long w_bins[8]; /* binned write */ long r_bins[8]; /* binned reads */#endif /* AIC7XXX_PROC_STATS */ } stats[MAX_TARGETS]; /* [(channel << 3)|target] */#if 0 struct target_cmd *targetcmds; unsigned int num_targetcmds;#endif};/* * Valid SCSIRATE values. (p. 3-17) * Provides a mapping of transfer periods in ns/4 to the proper value to * stick in the SCSIRATE reg to use that transfer rate. */#define AHC_SYNCRATE_ULTRA2 0#define AHC_SYNCRATE_ULTRA 2#define AHC_SYNCRATE_FAST 5static struct aic7xxx_syncrate { /* Rates in Ultra mode have bit 8 of sxfr set */#define ULTRA_SXFR 0x100 int sxfr_ultra2; int sxfr; unsigned char period; const char *rate[2];} aic7xxx_syncrates[] = { { 0x13, 0x000, 10, {"40.0", "80.0"} }, { 0x14, 0x000, 11, {"33.0", "66.6"} }, { 0x15, 0x100, 12, {"20.0", "40.0"} }, { 0x16, 0x110, 15, {"16.0", "32.0"} }, { 0x17, 0x120, 18, {"13.4", "26.8"} }, { 0x18, 0x000, 25, {"10.0", "20.0"} }, { 0x19, 0x010, 31, {"8.0", "16.0"} }, { 0x1a, 0x020, 37, {"6.67", "13.3"} }, { 0x1b, 0x030, 43, {"5.7", "11.4"} }, { 0x10, 0x040, 50, {"5.0", "10.0"} }, { 0x00, 0x050, 56, {"4.4", "8.8" } }, { 0x00, 0x060, 62, {"4.0", "8.0" } }, { 0x00, 0x070, 68, {"3.6", "7.2" } }, { 0x00, 0x000, 0, {NULL, NULL} },};#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \ (((scb->hscb)->target_channel_lun >> 4) & 0xf), \ ((scb->hscb)->target_channel_lun & 0x07)#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01), \ ((cmd->target) & 0x0f), \ ((cmd->lun) & 0x07)#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3))/* * A nice little define to make doing our printks a little easier */#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "/* * XXX - these options apply unilaterally to _all_ 274x/284x/294x * cards in the system. This should be fixed. Exceptions to this * rule are noted in the comments. *//* * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This * has no effect on any later resets that might occur due to things like * SCSI bus timeouts. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -