initio.c
来自「linux 内核源代码」· C语言 代码 · 共 2,386 行 · 第 1/5 页
C
2,386 行
int i; u16 chksum = 0; u16 *np, *np1; i91unvramp = &i91unvram; /* Calculate checksum first */ np = (u16 *) i91udftNvRam; for (i = 0; i < 31; i++) chksum += *np++; *np = chksum; initio_se2_ew_en(base); /* Enable write */ np = (u16 *) i91udftNvRam; np1 = (u16 *) i91unvramp; for (i = 0; i < 32; i++, np++, np1++) { if (*np != *np1) initio_se2_wr(base, i, *np); } initio_se2_ew_ds(base); /* Disable write */}/** * initio_read_eeprom - Retrieve configuration * @base: Base of InitIO Host Adapter * * Retrieve the host adapter configuration data from E2Prom. If the * data is invalid then the defaults are used and are also restored * into the E2PROM. This forms the access point for the SCSI driver * into the E2PROM layer, the other functions for the E2PROM are all * internal use. * * Must be called single threaded, uses a shared global area. */static void initio_read_eeprom(unsigned long base){ u8 gctrl; i91unvramp = &i91unvram; /* Enable EEProm programming */ gctrl = inb(base + TUL_GCTRL); outb(gctrl | TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL); if (initio_se2_rd_all(base) != 1) { initio_se2_update_all(base); /* setup default pattern */ initio_se2_rd_all(base); /* load again */ } /* Disable EEProm programming */ gctrl = inb(base + TUL_GCTRL); outb(gctrl & ~TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);}/** * initio_stop_bm - stop bus master * @host: InitIO we are stopping * * Stop any pending DMA operation, aborting the DMA if neccessary */static void initio_stop_bm(struct initio_host * host){ if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */ outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd); /* wait Abort DMA xfer done */ while ((inb(host->addr + TUL_Int) & XABT) == 0) cpu_relax(); } outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);}/** * initio_reset_scsi - Reset SCSI host controller * @host: InitIO host to reset * @seconds: Recovery time * * Perform a full reset of the SCSI subsystem. */static int initio_reset_scsi(struct initio_host * host, int seconds){ outb(TSC_RST_BUS, host->addr + TUL_SCtrl0); while (!((host->jsint = inb(host->addr + TUL_SInt)) & TSS_SCSIRST_INT)) cpu_relax(); /* reset tulip chip */ outb(0, host->addr + TUL_SSignal); /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */ /* SONY 5200 tape drive won't work if only stall for 1 sec */ /* FIXME: this is a very long busy wait right now */ initio_do_pause(seconds * HZ); inb(host->addr + TUL_SInt); return SCSI_RESET_SUCCESS;}/** * initio_init - set up an InitIO host adapter * @host: InitIO host adapter * @num_scbs: Number of SCBS * @bios_addr: BIOS address * * Set up the host adapter and devices according to the configuration * retrieved from the E2PROM. * * Locking: Calls E2PROM layer code which is not re-enterable so must * run single threaded for now. */static void initio_init(struct initio_host * host, u8 *bios_addr){ int i; u8 *flags; u8 *heads; /* Get E2Prom configuration */ initio_read_eeprom(host->addr); if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8) host->max_tar = 8; else host->max_tar = 16; host->config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1; host->scsi_id = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID; host->idmask = ~(1 << host->scsi_id);#ifdef CHK_PARITY /* Enable parity error response */ outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD);#endif /* Mask all the interrupt */ outb(0x1F, host->addr + TUL_Mask); initio_stop_bm(host); /* --- Initialize the tulip --- */ outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0); /* program HBA's SCSI ID */ outb(host->scsi_id << 4, host->addr + TUL_SScsiId); /* Enable Initiator Mode ,phase latch,alternate sync period mode, disable SCSI reset */ if (host->config & HCC_EN_PAR) host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR); else host->sconf1 = (TSC_INITDEFAULT); outb(host->sconf1, host->addr + TUL_SConfig); /* Enable HW reselect */ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); outb(0, host->addr + TUL_SPeriod); /* selection time out = 250 ms */ outb(153, host->addr + TUL_STimeOut); /* Enable SCSI terminator */ outb((host->config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)), host->addr + TUL_XCtrl); outb(((host->config & HCC_AUTO_TERM) >> 4) | (inb(host->addr + TUL_GCTRL1) & 0xFE), host->addr + TUL_GCTRL1); for (i = 0, flags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config), heads = bios_addr + 0x180; i < host->max_tar; i++, flags++) { host->targets[i].flags = *flags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE); if (host->targets[i].flags & TCF_EN_255) host->targets[i].drv_flags = TCF_DRV_255_63; else host->targets[i].drv_flags = 0; host->targets[i].js_period = 0; host->targets[i].sconfig0 = host->sconf1; host->targets[i].heads = *heads++; if (host->targets[i].heads == 255) host->targets[i].drv_flags = TCF_DRV_255_63; else host->targets[i].drv_flags = 0; host->targets[i].sectors = *heads++; host->targets[i].flags &= ~TCF_BUSY; host->act_tags[i] = 0; host->max_tags[i] = 0xFF; } /* for */ printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n", host->addr, host->pci_dev->irq, host->bios_addr, host->scsi_id); /* Reset SCSI Bus */ if (host->config & HCC_SCSI_RESET) { printk(KERN_INFO "i91u: Reset SCSI Bus ... \n"); initio_reset_scsi(host, 10); } outb(0x17, host->addr + TUL_SCFG1); outb(0xE9, host->addr + TUL_SIntEnable);}/** * initio_alloc_scb - Allocate an SCB * @host: InitIO host we are allocating for * * Walk the SCB list for the controller and allocate a free SCB if * one exists. */static struct scsi_ctrl_blk *initio_alloc_scb(struct initio_host *host){ struct scsi_ctrl_blk *scb; unsigned long flags; spin_lock_irqsave(&host->avail_lock, flags); if ((scb = host->first_avail) != NULL) {#if DEBUG_QUEUE printk("find scb at %p\n", scb);#endif if ((host->first_avail = scb->next) == NULL) host->last_avail = NULL; scb->next = NULL; scb->status = SCB_RENT; } spin_unlock_irqrestore(&host->avail_lock, flags); return scb;}/** * initio_release_scb - Release an SCB * @host: InitIO host that owns the SCB * @cmnd: SCB command block being returned * * Return an allocated SCB to the host free list */static void initio_release_scb(struct initio_host * host, struct scsi_ctrl_blk * cmnd){ unsigned long flags;#if DEBUG_QUEUE printk("Release SCB %p; ", cmnd);#endif spin_lock_irqsave(&(host->avail_lock), flags); cmnd->srb = NULL; cmnd->status = 0; cmnd->next = NULL; if (host->last_avail != NULL) { host->last_avail->next = cmnd; host->last_avail = cmnd; } else { host->first_avail = cmnd; host->last_avail = cmnd; } spin_unlock_irqrestore(&(host->avail_lock), flags);}/***************************************************************************/static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp){#if DEBUG_QUEUE printk("Append pend SCB %p; ", scbp);#endif scbp->status = SCB_PEND; scbp->next = NULL; if (host->last_pending != NULL) { host->last_pending->next = scbp; host->last_pending = scbp; } else { host->first_pending = scbp; host->last_pending = scbp; }}/***************************************************************************/static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp){#if DEBUG_QUEUE printk("Push pend SCB %p; ", scbp);#endif scbp->status = SCB_PEND; if ((scbp->next = host->first_pending) != NULL) { host->first_pending = scbp; } else { host->first_pending = scbp; host->last_pending = scbp; }}static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host){ struct scsi_ctrl_blk *first; first = host->first_pending; while (first != NULL) { if (first->opcode != ExecSCSI) return first; if (first->tagmsg == 0) { if ((host->act_tags[first->target] == 0) && !(host->targets[first->target].flags & TCF_BUSY)) return first; } else { if ((host->act_tags[first->target] >= host->max_tags[first->target]) | (host->targets[first->target].flags & TCF_BUSY)) { first = first->next; continue; } return first; } first = first->next; } return first;}static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb){ struct scsi_ctrl_blk *tmp, *prev;#if DEBUG_QUEUE printk("unlink pend SCB %p; ", scb);#endif prev = tmp = host->first_pending; while (tmp != NULL) { if (scb == tmp) { /* Unlink this SCB */ if (tmp == host->first_pending) { if ((host->first_pending = tmp->next) == NULL) host->last_pending = NULL; } else { prev->next = tmp->next; if (tmp == host->last_pending) host->last_pending = prev; } tmp->next = NULL; break; } prev = tmp; tmp = tmp->next; }}static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp){#if DEBUG_QUEUE printk("append busy SCB %p; ", scbp);#endif if (scbp->tagmsg) host->act_tags[scbp->target]++; else host->targets[scbp->target].flags |= TCF_BUSY; scbp->status = SCB_BUSY; scbp->next = NULL; if (host->last_busy != NULL) { host->last_busy->next = scbp; host->last_busy = scbp; } else { host->first_busy = scbp; host->last_busy = scbp; }}/***************************************************************************/static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host){ struct scsi_ctrl_blk *tmp; if ((tmp = host->first_busy) != NULL) { if ((host->first_busy = tmp->next) == NULL) host->last_busy = NULL; tmp->next = NULL; if (tmp->tagmsg) host->act_tags[tmp->target]--; else host->targets[tmp->target].flags &= ~TCF_BUSY; }#if DEBUG_QUEUE printk("Pop busy SCB %p; ", tmp);#endif return tmp;}/***************************************************************************/static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb){ struct scsi_ctrl_blk *tmp, *prev;#if DEBUG_QUEUE printk("unlink busy SCB %p; ", scb);#endif prev = tmp = host->first_busy; while (tmp != NULL) { if (scb == tmp) { /* Unlink this SCB */ if (tmp == host->first_busy) { if ((host->first_busy = tmp->next) == NULL) host->last_busy = NULL; } else { prev->next = tmp->next; if (tmp == host->last_busy) host->last_busy = prev; } tmp->next = NULL; if (tmp->tagmsg) host->act_tags[tmp->target]--; else host->targets[tmp->target].flags &= ~TCF_BUSY; break; } prev = tmp; tmp = tmp->next; } return;}struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun){ struct scsi_ctrl_blk *tmp, *prev; u16 scbp_tarlun; prev = tmp = host->first_busy; while (tmp != NULL) { scbp_tarlun = (tmp->lun << 8) | (tmp->target); if (scbp_tarlun == tarlun) { /* Unlink this SCB */ break; } prev = tmp; tmp = tmp->next; }#if DEBUG_QUEUE printk("find busy SCB %p; ", tmp);#endif return tmp;}static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp){#if DEBUG_QUEUE printk("append done SCB %p; ", scbp);#endif scbp->status = SCB_DONE; scbp->next = NULL; if (host->last_done != NULL) { host->last_done->next = scbp; host->last_done = scbp; } else { host->first_done = scbp; host->last_done = scbp; }}struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host){ struct scsi_ctrl_blk *tmp; if ((tmp = host->first_done) != NULL) { if ((host->first_done = tmp->next) == NULL) host->last_done = NULL; tmp->next = NULL; }#if DEBUG_QUEUE printk("find done SCB %p; ",tmp);#endif return tmp;}static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp){ unsigned long flags; struct scsi_ctrl_blk *tmp, *prev; spin_lock_irqsave(&host->semaph_lock, flags);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?