📄 eata.c
字号:
link_suffix = ", sorted"; else link_suffix = ", unsorted"; } if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) { dev->tagged_queue = 1; dev->current_tag = 1; } 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_AUX_STATUS) & ABSY_ASSERTED) { udelay(1L); if (--loop == 0) return TRUE; } return FALSE;}static inline int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) { if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return TRUE; if ((addr = V2DEV(addr))) { outb((char) (addr >> 24), iobase + REG_LOW); outb((char) (addr >> 16), iobase + REG_LM); outb((char) (addr >> 8), iobase + REG_MID); outb((char) addr, iobase + REG_MSB); } outb(cmd, iobase + REG_CMD); return FALSE;}static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) { unsigned int loop = MAXLOOP; ushort *p; for (p = start; p <= end; p++) { while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) { udelay(1L); if (--loop == 0) return TRUE; } loop = MAXLOOP; *p = inw(iobase); } return FALSE;}static inline void tune_pci_port(unsigned long port_base) {#if defined(CONFIG_PCI) unsigned int addr, k; struct pci_dev *dev = NULL; if (!pci_present()) return; for (k = 0; k < MAX_PCI; k++) { if (!(dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break; addr = pci_resource_start (dev, 0); if (pci_enable_device (dev)) continue;#if defined(DEBUG_PCI_DETECT) printk("%s: tune_pci_port, bus %d, devfn 0x%x, addr 0x%x.\n", driver_name, dev->bus->number, dev->devfn, addr);#endif if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) { pci_set_master(dev); return; } }#endif /* end CONFIG_PCI */ return;}static inline int get_pci_irq(unsigned long port_base, unsigned char *apic_irq) {#if defined(CONFIG_PCI) unsigned int addr; struct pci_dev *dev = NULL; if (!pci_present()) return FALSE; while((dev = pci_find_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { if (pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &addr)) continue;#if defined(DEBUG_PCI_DETECT) printk("%s: get_pci_irq, bus %d, devfn 0x%x, addr 0x%x, apic_irq %u.\n", driver_name, dev->bus->number, dev->devfn, addr, dev->irq);#endif if ((addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0 == port_base) { *apic_irq = dev->irq; return TRUE; } }#endif /* end CONFIG_PCI */ 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 protocol_rev, apic_irq; struct eata_info info; char *bus_type, dma_name[16], tag_type; /* Allowed DMA channels for ISA (0 indicates reserved) */ unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; 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 (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE; /* Read the info structure */ if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) return FALSE; /* Check the controller "EATA" signature */ if (info.sign != EATA_SIGNATURE) return FALSE; if (DEV2H(info.data_len) < EATA_2_0A_SIZE) { printk("%s: config structure size (%d bytes) too short, detaching.\n", name, DEV2H(info.data_len)); return FALSE; } else if (DEV2H(info.data_len) == EATA_2_0A_SIZE) protocol_rev = 'A'; else if (DEV2H(info.data_len) == EATA_2_0B_SIZE) protocol_rev = 'B'; else protocol_rev = 'C'; if (!setup_done && j > 0 && j <= MAX_PCI) { bus_type = "PCI"; subversion = ESA; } else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) { bus_type = "PCI"; subversion = ESA; } else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) { bus_type = "EISA"; subversion = ESA; } else if (protocol_rev == 'C' && !info.eisa && !info.pci) { bus_type = "ISA"; subversion = ISA; } else if (port_base > MAX_ISA_ADDR) { bus_type = "PCI"; subversion = ESA; } else { bus_type = "ISA"; subversion = ISA; } if (!info.haaval || info.ata) { printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", name, port_base, bus_type, info.haaval, info.ata); return FALSE; } if (info.drqvld) { if (subversion == ESA) printk("%s: warning, weird %s board using DMA.\n", name, bus_type); subversion = ISA; dma_channel = dma_channel_table[3 - info.drqx]; } else { if (subversion == ISA) printk("%s: warning, weird %s board not using DMA.\n", name, bus_type); subversion = ESA; dma_channel = NO_DMA; } if (!info.dmasup) printk("%s: warning, DMA protocol support not asserted.\n", name); irq = info.irq; if (subversion == ESA && !info.irq_tr) printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", name, irq); if (get_pci_irq(port_base, &apic_irq) && (irq != apic_irq)) { printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, apic_irq); irq = apic_irq; } /* 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 defined(FORCE_CONFIG) { struct eata_config config; /* Set board configuration */ memset((char *)&config, 0, sizeof(struct eata_config)); config.len = (ushort) htons((ushort)510); config.ocena = TRUE; if (do_dma(port_base, (unsigned long)&config, SET_CONFIG_DMA)) { printk("%s: busy timeout sending configuration, detaching.\n", name); return FALSE; } }#endif 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]->dma_channel = dma_channel; sh[j]->irq = irq; sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size); sh[j]->this_id = (ushort) info.host_addr[3]; sh[j]->can_queue = (ushort) ntohs(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; sh[j]->select_queue_depths = select_queue_depths; /* 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)->subversion = subversion; HD(j)->protocol_rev = protocol_rev; HD(j)->board_number = j; if (HD(j)->subversion == ESA) sh[j]->unchecked_isa_dma = FALSE; 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); } strcpy(BN(j), name); /* DPT PM2012 does not allow to detect sg_tablesize correctly */ if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) { printk("%s: detect, wrong n. of SG lists %d, fixed.\n", BN(j), sh[j]->sg_tablesize); sh[j]->sg_tablesize = MAX_SGLIST; } /* DPT PM2012 does not allow to detect can_queue correctly */ if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue < 2) { printk("%s: detect, wrong n. of mbox %d, fixed.\n", BN(j), sh[j]->can_queue); sh[j]->can_queue = MAX_MAILBOXES; } if (protocol_rev != 'A') { if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL) sh[j]->max_channel = info.max_chan; if (info.max_id > 7 && info.max_id < MAX_TARGET) sh[j]->max_id = info.max_id + 1; if (info.large_sg && sh[j]->sg_tablesize == MAX_SGLIST) sh[j]->sg_tablesize = MAX_LARGE_SGLIST; } if (protocol_rev == 'C') { if (info.max_lun > 7 && info.max_lun < MAX_LUN) sh[j]->max_lun = info.max_lun + 1; } 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); eata2x_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 (tagged_comm) { if (tag_mode == TAG_SIMPLE) tag_type = '1'; else if (tag_mode == TAG_HEAD) tag_type = '2'; else if (tag_mode == TAG_ORDERED) tag_type = '3'; else tag_type = 'y'; } else tag_type = 'n'; if (j == 0) { printk("EATA/DMA 2.0x: Copyright (C) 1994-2000 Dario Ballabio.\n"); printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c.\n", driver_name, tag_type, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), YESNO(ext_tran)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -