📄 u14-34f.c
字号:
#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 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[] = { /* 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;static int ext_tran = FALSE;static char *boot_options;#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; 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 = ", soft-tagged"; else if (dev->tagged_supported && TLDEV(dev->type)) tag_suffix = ", tagged"; 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); } 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 time = jiffies; while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); 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;}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) */ unsigned long bios_segment_table[8] = { 0, 0xc4000, 0xc8000, 0xcc000, 0xd0000, 0xd4000, 0xd8000, 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)) {#if defined(DEBUG_DETECT) printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);#endif 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; sh[j] = scsi_register(tpnt, sizeof(struct hostdata)); if (sh[j] == NULL) { printk("%s: unable to register host, detaching.\n", name); free_irq(irq, &sha[j]); if (subversion == ISA) free_dma(dma_channel); return FALSE; } sh[j]->io_port = port_base; sh[j]->unique_id = port_base; sh[j]->n_io_port = REGION_SIZE; sh[j]->base = bios_segment_table[config_1.bios_segment]; sh[j]->irq = irq; sh[j]->sg_tablesize = MAX_SGLIST; sh[j]->this_id = config_2.ha_scsi_id; sh[j]->can_queue = MAX_MAILBOXES; sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; sh[j]->select_queue_depths = select_queue_depths;#if defined(DEBUG_DETECT) { unsigned char sys_mask, lcl_mask; sys_mask = inb(sh[j]->io_port + REG_SYS_MASK); lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK); printk("SYS_MASK 0x%x, LCL_MASK 0x%x.\n", sys_mask, lcl_mask); }#endif /* Probably a bogus host scsi id, set it to the dummy value */ if (sh[j]->this_id == 0) sh[j]->this_id = -1; /* If BIOS is disabled, force enable interrupts */ if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK); /* Register the I/O space that we use */ request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name); memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->heads = mapping_table[config_2.mapping_mode].heads; HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors; HD(j)->subversion = subversion; HD(j)->board_number = j; if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST; if (HD(j)->subversion == ESA) { sh[j]->unchecked_isa_dma = FALSE; sh[j]->dma_channel = NO_DMA; sprintf(BN(j), "U34F%d", j); bus_type = "VESA"; } else { unsigned long flags; scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); release_dma_lock(flags); sh[j]->dma_channel = dma_channel; sprintf(BN(j), "U14F%d", j); bus_type = "ISA"; } sh[j]->max_channel = MAX_CHANNEL - 1; sh[j]->max_id = MAX_TARGET; sh[j]->max_lun = MAX_LUN; if (HD(j)->subversion == ISA && !board_inquiry(j)) { HD(j)->board_id[40] = 0; if (strcmp(&HD(j)->board_id[32], "06000600")) { printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]); printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n", BN(j), &HD(j)->board_id[32]); sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; sh[j]->sg_tablesize = MAX_SAFE_SGLIST; } } if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); else sprintf(dma_name, "DMA %u", dma_channel); for (i = 0; i < sh[j]->can_queue; i++) if (! ((&HD(j)->cp[i])->sglist = kmalloc( sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); u14_34f_release(sh[j]); return FALSE; } if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) max_queue_depth = MAX_TAGGED_CMD_PER_LUN; if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; if (j == 0) { printk("UltraStor 14F/34F: Copyright (C) 1994-2000 Dario Ballabio.\n"); printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n", driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -