📄 ultrastor.c
字号:
in_byte = inb(U14F_PRODUCT_ID(config.port_address)); if (in_byte != US14F_PRODUCT_ID_0) {#if (ULTRASTOR_DEBUG & UD_DETECT)# ifdef PORT_OVERRIDE printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);# else printk("US14F: detect: no adapter at port %03X\n", config.port_address);# endif#endif#ifdef PORT_OVERRIDE return FALSE;#else continue;#endif } in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1); /* Only upper nibble is significant for Product ID 1 */ if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {#if (ULTRASTOR_DEBUG & UD_DETECT)# ifdef PORT_OVERRIDE printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);# else printk("US14F: detect: no adapter at port %03X\n", config.port_address);# endif#endif#ifdef PORT_OVERRIDE return FALSE;#else continue;#endif } version_byte = in_byte;#ifndef PORT_OVERRIDE break; } if (i == ARRAY_SIZE(ultrastor_ports_14f)) {# if (ULTRASTOR_DEBUG & UD_DETECT) printk("US14F: detect: no port address found!\n");# endif return FALSE; }#endif#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US14F: detect: adapter found at port address %03X\n", config.port_address);#endif /* Set local doorbell mask to disallow bus reset unless ultrastor_bus_reset is true. */ outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address)); /* All above tests passed, must be the right thing. Get some useful info. */ snarf_region(config.port_address, 0x0c); /* Register the I/O space that we use */ *(char *)&config_1 = inb(CONFIG(config.port_address + 0)); *(char *)&config_2 = inb(CONFIG(config.port_address + 1)); config.bios_segment = bios_segment_table[config_1.bios_segment]; config.doorbell_address = config.port_address; config.ogm_address = config.port_address + 0x8; config.icm_address = config.port_address + 0xC; config.interrupt = interrupt_table_14f[config_1.interrupt]; config.ha_scsi_id = config_2.ha_scsi_id; config.heads = mapping_table[config_2.mapping_mode].heads; config.sectors = mapping_table[config_2.mapping_mode].sectors; config.bios_drive_number = config_2.bios_drive_number; config.subversion = (version_byte & 0x0F); if (config.subversion == U34F) config.dma_channel = 0; else config.dma_channel = dma_channel_table_14f[config_1.dma_channel]; if (!config.bios_segment) {#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US14F: detect: not detected.\n");#endif return FALSE; } /* Final consistancy check, verify previous info. */ if (config.subversion != U34F) if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US14F: detect: consistancy check failed\n");#endif return FALSE; } /* If we were TRULY paranoid, we could issue a host adapter inquiry command here and verify the data returned. But frankly, I'm exhausted! */ /* Finally! Now I'm satisfied... */#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US14F: detect: detect succeeded\n" " Port address: %03X\n" " BIOS segment: %05X\n" " Interrupt: %u\n" " DMA channel: %u\n" " H/A SCSI ID: %u\n" " Subversion: %u\n", config.port_address, config.bios_segment, config.interrupt, config.dma_channel, config.ha_scsi_id, config.subversion);#endif config.host_number = hostnum; scsi_hosts[hostnum].this_id = config.ha_scsi_id; scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);#if ULTRASTOR_MAX_CMDS > 1 config.mscp_free = ~0;#endif if (request_irq(config.interrupt, ultrastor_interrupt)) { printk("Unable to allocate IRQ%u for UltraStor controller.\n", config.interrupt); return FALSE; } if (config.dma_channel && request_dma(config.dma_channel)) { printk("Unable to allocate DMA channel %u for UltraStor controller.\n", config.dma_channel); free_irq(config.interrupt); return FALSE; } scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG; printk("UltraStor driver version" VERSION ". Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG); return TRUE;}static int ultrastor_24f_detect(int hostnum){ register int i;#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US24F: detect");#endif /* probe each EISA slot at slot address C80 */ for (i = 1; i < 15; i++) { unsigned char config_1, config_2; unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT; if (inb(addr) != US24F_PRODUCT_ID_0 && inb(addr+1) != US24F_PRODUCT_ID_1 && inb(addr+2) != US24F_PRODUCT_ID_2) continue; config.revision = inb(addr+3); config.slot = i; if (! (inb(addr+4) & 1)) {#if (ULTRASTOR_DEBUG & UD_DETECT) printk("U24F: found disabled card in slot %u\n", i);#endif continue; }#if (ULTRASTOR_DEBUG & UD_DETECT) printk("U24F: found card in slot %u\n", i);#endif config_1 = inb(addr + 5); config.bios_segment = bios_segment_table[config_1 & 7]; switch(config_1 >> 4) { case 1: config.interrupt = 15; break; case 2: config.interrupt = 14; break; case 4: config.interrupt = 11; break; case 8: config.interrupt = 10; break; default: printk("U24F: invalid IRQ\n"); return FALSE; } if (request_irq(config.interrupt, ultrastor_interrupt)) { printk("Unable to allocate IRQ%u for UltraStor controller.\n", config.interrupt); return FALSE; } /* BIOS addr set */ /* base port set */ config.port_address = addr; config.doorbell_address = addr + 12; config.ogm_address = addr + 0x17; config.icm_address = addr + 0x1C; config_2 = inb(addr + 7); config.ha_scsi_id = config_2 & 7; config.heads = mapping_table[(config_2 >> 3) & 3].heads; config.sectors = mapping_table[(config_2 >> 3) & 3].sectors;#if (ULTRASTOR_DEBUG & UD_DETECT) printk("US24F: detect: detect succeeded\n" " Port address: %03X\n" " BIOS segment: %05X\n" " Interrupt: %u\n" " H/A SCSI ID: %u\n", config.port_address, config.bios_segment, config.interrupt, config.ha_scsi_id);#endif config.host_number = hostnum; scsi_hosts[hostnum].this_id = config.ha_scsi_id; scsi_hosts[hostnum].unchecked_isa_dma = 0; scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;#if ULTRASTOR_MAX_CMDS > 1 config.mscp_free = ~0;#endif /* Mark ICM and OGM free */ outb(0, addr + 0x16); outb(0, addr + 0x1B); /* Set local doorbell mask to disallow bus reset unless ultrastor_bus_reset is true. */ outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12)); outb(0x02, SYS_DOORBELL_MASK(addr+12)); printk("UltraStor driver version " VERSION ". Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG); return TRUE; } return FALSE;}int ultrastor_detect(int hostnum){ return ultrastor_14f_detect(hostnum) || ultrastor_24f_detect(hostnum);}const char *ultrastor_info(void){ static char buf[64]; if (config.slot) sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u\n", config.slot, config.interrupt); else if (config.subversion) sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u\n", config.port_address, (int)config.bios_segment, config.interrupt); else sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n", config.port_address, (int)config.bios_segment, config.interrupt, config.dma_channel); return buf;}static inline void build_sg_list(register struct mscp *mscp, Scsi_Cmnd *SCpnt){ struct scatterlist *sl; long transfer_length = 0; int i, max; sl = (struct scatterlist *) SCpnt->request_buffer; max = SCpnt->use_sg; for (i = 0; i < max; i++) { mscp->sglist[i].address = (unsigned int)sl[i].address; mscp->sglist[i].num_bytes = sl[i].length; transfer_length += sl[i].length; } mscp->number_of_sg_list = max; mscp->transfer_data = (unsigned int)mscp->sglist; /* ??? May not be necessary. Docs are unclear as to whether transfer length field is ignored or whether it should be set to the total number of bytes of the transfer. */ mscp->transfer_data_length = transfer_length;}int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)){ register struct mscp *my_mscp;#if ULTRASTOR_MAX_CMDS > 1 int mscp_index;#endif unsigned int status; int flags; /* Next test is for debugging; "can't happen" */ if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0) panic("ultrastor_queuecommand: no free MSCP\n"); mscp_index = find_and_clear_bit_16(&config.mscp_free); /* Has the command been aborted? */ if (xchgb(0xff, &config.aborted[mscp_index]) != 0) { status = DID_ABORT << 16; goto aborted; } my_mscp = &config.mscp[mscp_index];#if 1 /* This way is faster. */ *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);#else my_mscp->opcode = OP_SCSI; my_mscp->xdir = DTD_SCSI; my_mscp->dcn = FALSE;#endif /* Tape drives don't work properly if the cache is used. The SCSI READ command for a tape doesn't have a block offset, and the adapter incorrectly assumes that all reads from the tape read the same blocks. Results will depend on read buffer size and other disk activity. ??? Which other device types should never use the cache? */ my_mscp->ca = scsi_devices[SCpnt->index].type != TYPE_TAPE; my_mscp->target_id = SCpnt->target; my_mscp->ch_no = 0; my_mscp->lun = SCpnt->lun; if (SCpnt->use_sg) { /* Set scatter/gather flag in SCSI command packet */ my_mscp->sg = TRUE; build_sg_list(my_mscp, SCpnt); } else { /* Unset scatter/gather flag in SCSI command packet */ my_mscp->sg = FALSE; my_mscp->transfer_data = (unsigned int)SCpnt->request_buffer; my_mscp->transfer_data_length = SCpnt->request_bufflen; } my_mscp->command_link = 0; /*???*/ my_mscp->scsi_command_link_id = 0; /*???*/ my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer; my_mscp->length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd); memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs); my_mscp->adapter_status = 0; my_mscp->target_status = 0; my_mscp->sense_data = (unsigned int)&SCpnt->sense_buffer; my_mscp->done = done; my_mscp->SCint = SCpnt; SCpnt->host_scribble = (unsigned char *)my_mscp; /* Find free OGM slot. On 24F, look for OGM status byte == 0. On 14F and 34F, wait for local interrupt pending flag to clear. */ retry: if (config.slot) while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff); /* else??? */ while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) && config.aborted[mscp_index] == 0xff); /* To avoid race conditions, make the code to write to the adapter atomic. This simplifies the abort code. */ save_flags(flags); cli(); if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) { restore_flags(flags); goto retry; } status = xchgb(0, &config.aborted[mscp_index]); if (status != 0xff) { restore_flags(flags);#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -