static ssize_t powertecscsi_store_term(struct device *dev, const char *buf, size_t len) { struct expansion_card *ec = ECARD_DEV(dev); struct Scsi_Host *host = ecard_get_drvdata(ec); if (len > 1) powertecscsi_terminator_ctl(host, buf[0] != '0'); return len; }
/* Prototype: int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) * Purpose : Set a driver specific function * Params : host - host to setup * : buffer - buffer containing string describing operation * : length - length of string * Returns : -EINVAL, or 0 */ static int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) { int ret = length; if (length >= 12 && strncmp(buffer, "POWERTECSCSI", 12) == 0) { buffer += 12; length -= 12; if (length >= 5 && strncmp(buffer, "term=", 5) == 0) { if (buffer[5] == '1') powertecscsi_terminator_ctl(host, 1); else if (buffer[5] == '0') powertecscsi_terminator_ctl(host, 0); else ret = -EINVAL; } else ret = -EINVAL; } else ret = -EINVAL; return ret; }
static int powertecscsi_probe(struct expansion_card *ec) { struct Scsi_Host *host; struct powertec_info *info; unsigned long base; int ret; base = ecard_address(ec, ECARD_IOC, ECARD_FAST); request_region(base + POWERTEC_FAS216_OFFSET, 16 << POWERTEC_FAS216_SHIFT, "powertec2-fas"); host = scsi_register(&powertecscsi_template, sizeof (struct powertec_info)); if (!host) { ret = -ENOMEM; goto out_region; } host->io_port = base; host->irq = ec->irq; host->dma_channel = ec->dma; ec->irqaddr = (unsigned char *)ioaddr(base + POWERTEC_INTR_STATUS); ec->irqmask = POWERTEC_INTR_BIT; ec->irq_data = (void *)(base + POWERTEC_INTR_CONTROL); ec->ops = (expansioncard_ops_t *)&powertecscsi_ops; info = (struct powertec_info *)host->hostdata; info->ec = ec; info->term_port = base + POWERTEC_TERM_CONTROL; powertecscsi_terminator_ctl(host, term[ec->slot_no]); info->info.scsi.io_port = host->io_port + POWERTEC_FAS216_OFFSET; info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT; info->info.scsi.irq = host->irq; info->info.ifcfg.clockrate = 40; /* MHz */ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = 200; /* ns */ info->info.ifcfg.sync_max_depth = 7; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; info->info.ifcfg.capabilities = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; ret = fas216_init(host); if (ret) goto out_free; ret = request_irq(host->irq, powertecscsi_intr, SA_INTERRUPT, "powertec", &info->info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, host->irq, ret); goto out_release; } if (host->dma_channel != NO_DMA) { if (request_dma(host->dma_channel, "powertec")) { printk("scsi%d: DMA%d not free, using PIO\n", host->host_no, host->dma_channel); host->dma_channel = NO_DMA; } else { set_dma_speed(host->dma_channel, 180); info->info.ifcfg.capabilities |= FASCAP_DMA; } } ret = fas216_add(host); if (ret == 0) goto out; if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); free_irq(host->irq, host); out_release: fas216_release(host); out_free: scsi_unregister(host); out_region: release_region(base + POWERTEC_FAS216_OFFSET, 16 << POWERTEC_FAS216_SHIFT); out: return ret; }
static int __devinit powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) { struct Scsi_Host *host; struct powertec_info *info; unsigned long resbase, reslen; void __iomem *base; int ret; ret = ecard_request_resources(ec); if (ret) goto out; resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST); reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST); base = ioremap(resbase, reslen); if (!base) { ret = -ENOMEM; goto out_region; } host = scsi_host_alloc(&powertecscsi_template, sizeof (struct powertec_info)); if (!host) { ret = -ENOMEM; goto out_unmap; } ecard_set_drvdata(ec, host); info = (struct powertec_info *)host->hostdata; info->base = base; powertecscsi_terminator_ctl(host, term[ec->slot_no]); info->info.scsi.io_base = base + POWERTEC_FAS216_OFFSET; info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT; info->info.scsi.irq = ec->irq; info->info.scsi.dma = ec->dma; info->info.ifcfg.clockrate = 40; /* MHz */ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = 200; /* ns */ info->info.ifcfg.sync_max_depth = 7; info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; info->info.ifcfg.capabilities = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; ec->irqaddr = base + POWERTEC_INTR_STATUS; ec->irqmask = POWERTEC_INTR_BIT; ec->irq_data = info; ec->ops = &powertecscsi_ops; device_create_file(&ec->dev, &dev_attr_bus_term); ret = fas216_init(host); if (ret) goto out_free; ret = request_irq(ec->irq, powertecscsi_intr, SA_INTERRUPT, "powertec", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, ec->irq, ret); goto out_release; } if (info->info.scsi.dma != NO_DMA) { if (request_dma(info->info.scsi.dma, "powertec")) { printk("scsi%d: DMA%d not free, using PIO\n", host->host_no, info->info.scsi.dma); info->info.scsi.dma = NO_DMA; } else { set_dma_speed(info->info.scsi.dma, 180); info->info.ifcfg.capabilities |= FASCAP_DMA; } } ret = fas216_add(host, &ec->dev); if (ret == 0) goto out; if (info->info.scsi.dma != NO_DMA) free_dma(info->info.scsi.dma); free_irq(ec->irq, host); out_release: fas216_release(host); out_free: device_remove_file(&ec->dev, &dev_attr_bus_term); scsi_host_put(host); out_unmap: iounmap(base); out_region: ecard_release_resources(ec); out: return ret; }
/* Prototype: int powertecscsi_detect(Scsi_Host_Template * tpnt) * Purpose : initialises PowerTec SCSI driver * Params : tpnt - template for this SCSI adapter * Returns : >0 if host found, 0 otherwise. */ int powertecscsi_detect(Scsi_Host_Template *tpnt) { static const card_ids powertecscsi_cids[] = { POWERTECSCSI_LIST, { 0xffff, 0xffff} }; int count = 0; struct Scsi_Host *host; tpnt->proc_dir = &proc_scsi_powertec; memset(ecs, 0, sizeof (ecs)); ecard_startfind(); while (1) { PowerTecScsi_Info *info; ecs[count] = ecard_find(0, powertecscsi_cids); if (!ecs[count]) break; ecard_claim(ecs[count]); host = scsi_register(tpnt, sizeof (PowerTecScsi_Info)); if (!host) { ecard_release(ecs[count]); break; } host->io_port = ecard_address(ecs[count], ECARD_IOC, ECARD_FAST); host->irq = ecs[count]->irq; host->dma_channel = ecs[count]->dma; info = (PowerTecScsi_Info *)host->hostdata; info->control.term_port = host->io_port + POWERTEC_TERM_CONTROL; info->control.terms = term[count] ? POWERTEC_TERM_ENABLE : 0; powertecscsi_terminator_ctl(host, info->control.terms); info->info.scsi.io_port = host->io_port + POWERTEC_FAS216_OFFSET; info->info.scsi.io_shift= POWERTEC_FAS216_SHIFT; info->info.scsi.irq = host->irq; info->info.ifcfg.clockrate = POWERTEC_XTALFREQ; info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; info->info.ifcfg.cntl3 = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; ecs[count]->irqaddr = (unsigned char *) ioaddr(host->io_port + POWERTEC_INTR_STATUS); ecs[count]->irqmask = POWERTEC_INTR_BIT; ecs[count]->irq_data = (void *) (host->io_port + POWERTEC_INTR_CONTROL); ecs[count]->ops = (expansioncard_ops_t *)&powertecscsi_ops; request_region(host->io_port + POWERTEC_FAS216_OFFSET, 16 << POWERTEC_FAS216_SHIFT, "powertec2-fas"); if (host->irq != NO_IRQ && request_irq(host->irq, powertecscsi_intr, SA_INTERRUPT, "powertec", host)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", host->host_no, host->irq); host->irq = NO_IRQ; info->info.scsi.irq = NO_IRQ; } if (host->dma_channel != NO_DMA && request_dma(host->dma_channel, "powertec")) { printk("scsi%d: DMA%d not free, DMA disabled\n", host->host_no, host->dma_channel); host->dma_channel = NO_DMA; } fas216_init(host); ++count; } return count; }