📄 u14-34f.c
字号:
#define PRODUCT_ID2 0x40 /* NOTE: Only upper nibble is used *//* Subversion values */#define ISA 0#define ESA 1#define OP_HOST_ADAPTER 0x1#define OP_SCSI 0x2#define OP_RESET 0x4#define DTD_SCSI 0x0#define DTD_IN 0x1#define DTD_OUT 0x2#define DTD_NONE 0x3#define HA_CMD_INQUIRY 0x1#define HA_CMD_SELF_DIAG 0x2#define HA_CMD_READ_BUFF 0x3#define HA_CMD_WRITE_BUFF 0x4#undef DEBUG_LINKED_COMMANDS#undef DEBUG_DETECT#undef DEBUG_INTERRUPT#undef DEBUG_RESET#undef DEBUG_GENERATE_ERRORS#undef DEBUG_GENERATE_ABORTS#undef DEBUG_GEOMETRY#define MAX_ISA 3#define MAX_VESA 1#define MAX_EISA 0#define MAX_PCI 0#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)#define MAX_CHANNEL 1#define MAX_LUN 8#define MAX_TARGET 8#define MAX_MAILBOXES 16#define MAX_SGLIST 32#define MAX_SAFE_SGLIST 16#define MAX_INTERNAL_RETRIES 64#define MAX_CMD_PER_LUN 2#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)#define SKIP ULONG_MAX#define FALSE 0#define TRUE 1#define FREE 0#define IN_USE 1#define LOCKED 2#define IN_RESET 3#define IGNORE 4#define READY 5#define ABORTING 6#define NO_DMA 0xff#define MAXLOOP 10000#define REG_LCL_MASK 0#define REG_LCL_INTR 1#define REG_SYS_MASK 2#define REG_SYS_INTR 3#define REG_PRODUCT_ID1 4#define REG_PRODUCT_ID2 5#define REG_CONFIG1 6#define REG_CONFIG2 7#define REG_OGM 8#define REG_ICM 12#define REGION_SIZE 13#define BSY_ASSERTED 0x01#define IRQ_ASSERTED 0x01#define CMD_RESET 0xc0#define CMD_OGM_INTR 0x01#define CMD_CLR_INTR 0x01#define CMD_ENA_INTR 0x81#define ASOK 0x00#define ASST 0x91#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])#define YESNO(a) ((a) ? 'y' : 'n')#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)#define PACKED __attribute__((packed))struct sg_list { unsigned int address; /* Segment Address */ unsigned int num_bytes; /* Segment Length */ };/* MailBox SCSI Command Packet */struct mscp { unsigned char opcode: 3; /* type of command */ unsigned char xdir: 2; /* data transfer direction */ unsigned char dcn: 1; /* disable disconnect */ unsigned char ca: 1; /* use cache (if available) */ unsigned char sg: 1; /* scatter/gather operation */ unsigned char target: 3; /* SCSI target id */ unsigned char channel: 2; /* SCSI channel number */ unsigned char lun: 3; /* SCSI logical unit number */ unsigned int data_address PACKED; /* transfer data pointer */ unsigned int data_len PACKED; /* length in bytes */ unsigned int link_address PACKED; /* for linking command chains */ unsigned char clink_id; /* identifies command in chain */ unsigned char use_sg; /* (if sg is set) 8 bytes per list */ unsigned char sense_len; unsigned char scsi_cdbs_len; /* 6, 10, or 12 */ unsigned char scsi_cdbs[12]; /* SCSI commands */ unsigned char adapter_status; /* non-zero indicates HA error */ unsigned char target_status; /* non-zero indicates target error */ unsigned int sense_addr PACKED; Scsi_Cmnd *SCpnt; unsigned int index; /* cp index */ struct sg_list *sglist; };struct hostdata { struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ unsigned int last_cp_used; /* Index of last mailbox used */ unsigned int iocount; /* Total i/o done for this board */ int board_number; /* Number of this board */ char board_name[16]; /* Name of this board */ char board_id[256]; /* data from INQUIRY on this board */ int in_reset; /* True if board is doing a reset */ int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ unsigned int retries; /* Number of internal retries */ unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or ESA */ unsigned char heads; unsigned char sectors; /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */ unsigned char slot; };static struct Scsi_Host *sh[MAX_BOARDS + 1];static const char *driver_name = "Ux4F";static char sha[MAX_BOARDS];/* Initialize num_boards so that ihdlr can work while detect is in progress */static unsigned int num_boards = MAX_BOARDS;static unsigned long io_port[] __initdata = { /* Space for MAX_INT_PARAM ports usable while loading as a module */ SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, /* Possible ISA/VESA ports */ 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, /* End of list */ 0x0 };#define HD(board) ((struct hostdata *) &sh[board]->hostdata)#define BN(board) (HD(board)->board_name)#define SWAP_BYTE(x) ((unsigned long)( \ (((unsigned long)(x) & 0x000000ffU) << 24) | \ (((unsigned long)(x) & 0x0000ff00U) << 8) | \ (((unsigned long)(x) & 0x00ff0000U) >> 8) | \ (((unsigned long)(x) & 0xff000000U) >> 24)))#if defined(__BIG_ENDIAN)#define H2DEV(x) SWAP_BYTE(x)#else#define H2DEV(x) (x)#endif#define DEV2H(x) H2DEV(x)#define V2DEV(addr) ((addr) ? H2DEV(virt_to_bus((void *)addr)) : 0)#define DEV2V(addr) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr)) : 0)static void do_interrupt_handler(int, void *, struct pt_regs *);static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);static int do_trace = FALSE;static int setup_done = FALSE;static int link_statistics = 0;static int ext_tran = FALSE;#if defined(HAVE_OLD_UX4F_FIRMWARE)static int have_old_firmware = TRUE;#elsestatic int have_old_firmware = FALSE;#endif#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)static int linked_comm = TRUE;#elsestatic int linked_comm = FALSE;#endif#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;#elsestatic int max_queue_depth = MAX_CMD_PER_LUN;#endifstatic void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) { Scsi_Device *dev; int j, ntag = 0, nuntag = 0, tqd, utqd; IRQ_FLAGS IRQ_LOCK_SAVE j = ((struct hostdata *) host->hostdata)->board_number; for(dev = devlist; dev; dev = dev->next) { if (dev->host != host) continue; if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) ntag++; else nuntag++; } utqd = MAX_CMD_PER_LUN; tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); if (tqd > max_queue_depth) tqd = max_queue_depth; if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN; for(dev = devlist; dev; dev = dev->next) { char *tag_suffix = "", *link_suffix = ""; if (dev->host != host) continue; if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) dev->queue_depth = tqd; else dev->queue_depth = utqd; if (TLDEV(dev->type)) { if (linked_comm && dev->queue_depth > 2) link_suffix = ", sorted"; else link_suffix = ", unsorted"; } if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue) tag_suffix = ", tagged"; else if (dev->tagged_supported && TLDEV(dev->type)) tag_suffix = ", untagged"; printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", BN(j), host->host_no, dev->channel, dev->id, dev->lun, dev->queue_depth, link_suffix, tag_suffix); } IRQ_UNLOCK_RESTORE return;}static inline int wait_on_busy(unsigned long iobase, unsigned int loop) { while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) { udelay(1L); if (--loop == 0) return TRUE; } return FALSE;}static int board_inquiry(unsigned int j) { struct mscp *cpp; unsigned int time, limit = 0; cpp = &HD(j)->cp[0]; memset(cpp, 0, sizeof(struct mscp)); cpp->opcode = OP_HOST_ADAPTER; cpp->xdir = DTD_IN; cpp->data_address = V2DEV(HD(j)->board_id); cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); cpp->scsi_cdbs_len = 6; cpp->scsi_cdbs[0] = HA_CMD_INQUIRY; if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { printk("%s: board_inquiry, adapter busy.\n", BN(j)); return TRUE; } HD(j)->cp_stat[0] = IGNORE; /* Clear the interrupt indication */ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); /* Store pointer in OGM address bytes */ outl(V2DEV(cpp), sh[j]->io_port + REG_OGM); /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); SPIN_UNLOCK IRQ_UNLOCK time = jiffies; while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); IRQ_LOCK SPIN_LOCK if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { HD(j)->cp_stat[0] = FREE; printk("%s: board_inquiry, err 0x%x.\n", BN(j), cpp->adapter_status); return TRUE; } return FALSE;}__initfunc (static inline int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt)) { unsigned char irq, dma_channel, subversion, i; unsigned char in_byte; char *bus_type, dma_name[16]; /* Allowed BIOS base addresses (NULL indicates reserved) */ void *bios_segment_table[8] = { NULL, (void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000, (void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000 }; /* Allowed IRQs */ unsigned char interrupt_table[4] = { 15, 14, 11, 10 }; /* Allowed DMA channels for ISA (0 indicates reserved) */ unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; /* Head/sector mappings */ struct { unsigned char heads; unsigned char sectors; } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } }; struct config_1 { unsigned char bios_segment: 3; unsigned char removable_disks_as_fixed: 1; unsigned char interrupt: 2; unsigned char dma_channel: 2; } config_1; struct config_2 { unsigned char ha_scsi_id: 3; unsigned char mapping_mode: 2; unsigned char bios_drive_number: 1; unsigned char tfr_port: 2; } config_2; char name[16]; sprintf(name, "%s%d", driver_name, j); if(check_region(port_base, REGION_SIZE)) { printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); return FALSE; } if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) return FALSE; in_byte = inb(port_base + REG_PRODUCT_ID2); if ((in_byte & 0xf0) != PRODUCT_ID2) return FALSE; *(char *)&config_1 = inb(port_base + REG_CONFIG1); *(char *)&config_2 = inb(port_base + REG_CONFIG2); irq = interrupt_table[config_1.interrupt]; dma_channel = dma_channel_table[config_1.dma_channel]; subversion = (in_byte & 0x0f); /* Board detected, allocate its IRQ */ if (request_irq(irq, do_interrupt_handler, SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), driver_name, (void *) &sha[j])) { printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); return FALSE; } if (subversion == ISA && request_dma(dma_channel, driver_name)) { printk("%s: unable to allocate DMA channel %u, detaching.\n", name, dma_channel); free_irq(irq, &sha[j]); return FALSE; } if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101) tpnt->use_new_eh_code = use_new_eh_code;#else use_new_eh_code = FALSE;#endif sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -