📄 sym53c500_cs.c
字号:
break; case 0x07: /* MESSAGE-IN */ VDEB(printk("SYM53C500: Message-In phase\n")); curSC->SCp.phase = message_in; curSC->SCp.Status = inb(port_base + SCSI_FIFO); curSC->SCp.Message = inb(port_base + SCSI_FIFO); VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); DEB(printk("Status = %02x Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message)); if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) { outb(SET_ATN, port_base + CMD_REG); /* Reject message */ DEB(printk("Discarding SAVE_POINTERS message\n")); } outb(MSG_ACCEPT, port_base + CMD_REG); break; }out: spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED;idle_out: curSC->SCp.phase = idle; curSC->scsi_done(curSC); goto out;}static voidSYM53C500_release(dev_link_t *link){ struct scsi_info_t *info = link->priv; struct Scsi_Host *shost = info->host; DEBUG(0, "SYM53C500_release(0x%p)\n", link); /* * Do this before releasing/freeing resources. */ scsi_remove_host(shost); /* * Interrupts getting hosed on card removal. Try * the following code, mostly from qlogicfas.c. */ if (shost->irq) free_irq(shost->irq, shost); if (shost->dma_channel != 0xff) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; scsi_host_put(shost);} /* SYM53C500_release */static const char*SYM53C500_info(struct Scsi_Host *SChost){ static char info_msg[256]; struct sym53c500_data *data = (struct sym53c500_data *)SChost->hostdata; DEB(printk("SYM53C500_info called\n")); (void)snprintf(info_msg, sizeof(info_msg), "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow"); return (info_msg);}static int SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ int i; int port_base = SCpnt->device->host->io_port; struct sym53c500_data *data = (struct sym53c500_data *)SCpnt->device->host->hostdata; VDEB(printk("SYM53C500_queue called\n")); DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, SCpnt->device->lun, SCpnt->request_bufflen)); VDEB(for (i = 0; i < SCpnt->cmd_len; i++) printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); VDEB(printk("\n")); data->current_SC = SCpnt; data->current_SC->scsi_done = done; data->current_SC->SCp.phase = command_ph; data->current_SC->SCp.Status = 0; data->current_SC->SCp.Message = 0; /* We are locked here already by the mid layer */ REG0(port_base); outb(SCpnt->device->id, port_base + DEST_ID); /* set destination */ outb(FLUSH_FIFO, port_base + CMD_REG); /* reset the fifos */ for (i = 0; i < SCpnt->cmd_len; i++) { outb(SCpnt->cmnd[i], port_base + SCSI_FIFO); } outb(SELECT_NO_ATN, port_base + CMD_REG); return 0;}static int SYM53C500_host_reset(struct scsi_cmnd *SCpnt){ int port_base = SCpnt->device->host->io_port; DEB(printk("SYM53C500_host_reset called\n")); SYM53C500_int_host_reset(port_base); return SUCCESS;}static int SYM53C500_biosparm(struct scsi_device *disk, struct block_device *dev, sector_t capacity, int *info_array){ int size; DEB(printk("SYM53C500_biosparm called\n")); size = capacity; info_array[0] = 64; /* heads */ info_array[1] = 32; /* sectors */ info_array[2] = size >> 11; /* cylinders */ if (info_array[2] > 1024) { /* big disk */ info_array[0] = 255; info_array[1] = 63; info_array[2] = size / (255 * 63); } return 0;}static ssize_tSYM53C500_show_pio(struct class_device *cdev, char *buf){ struct Scsi_Host *SHp = class_to_shost(cdev); struct sym53c500_data *data = (struct sym53c500_data *)SHp->hostdata; return snprintf(buf, 4, "%d\n", data->fast_pio);}static ssize_tSYM53C500_store_pio(struct class_device *cdev, const char *buf, size_t count){ int pio; struct Scsi_Host *SHp = class_to_shost(cdev); struct sym53c500_data *data = (struct sym53c500_data *)SHp->hostdata; pio = simple_strtoul(buf, NULL, 0); if (pio == 0 || pio == 1) { data->fast_pio = pio; return count; } else return -EINVAL;}/** SCSI HBA device attributes we want to* make available via sysfs.*/static struct class_device_attribute SYM53C500_pio_attr = { .attr = { .name = "fast_pio", .mode = (S_IRUGO | S_IWUSR), }, .show = SYM53C500_show_pio, .store = SYM53C500_store_pio,};static struct class_device_attribute *SYM53C500_shost_attrs[] = { &SYM53C500_pio_attr, NULL,};/** scsi_host_template initializer*/static struct scsi_host_template sym53c500_driver_template = { .module = THIS_MODULE, .name = "SYM53C500", .info = SYM53C500_info, .queuecommand = SYM53C500_queue, .eh_host_reset_handler = SYM53C500_host_reset, .bios_param = SYM53C500_biosparm, .proc_name = "SYM53C500", .can_queue = 1, .this_id = 7, .sg_tablesize = 32, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = SYM53C500_shost_attrs};#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)static voidSYM53C500_config(dev_link_t *link){ client_handle_t handle = link->handle; struct scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; int i, last_ret, last_fn; int irq_level, port_base; unsigned short tuple_data[32]; struct Scsi_Host *host; struct scsi_host_template *tpnt = &sym53c500_driver_template; struct sym53c500_data *data; DEBUG(0, "SYM53C500_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *)tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_MANFID; if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) info->manf_id = le16_to_cpu(tuple.TupleData[0]); /* Configure card */ link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { if (pcmcia_get_tuple_data(handle, &tuple) != 0 || pcmcia_parse_tuple(handle, &tuple, &parse) != 0) goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; if (link->io.BasePort1 != 0) { i = pcmcia_request_io(handle, &link->io); if (i == CS_SUCCESS) break; }next_entry: CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); /* * That's the trouble with copying liberally from another driver. * Some things probably aren't relevant, and I suspect this entire * section dealing with manufacturer IDs can be scrapped. --rct */ if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { /* set ATAcmd */ outb(0xb4, link->io.BasePort1 + 0xd); outb(0x24, link->io.BasePort1 + 0x9); outb(0x04, link->io.BasePort1 + 0xd); } /* * irq_level == 0 implies tpnt->can_queue == 0, which * is not supported in 2.6. Thus, only irq_level > 0 * will be allowed. * * Possible port_base values are as follows: * * 0x130, 0x230, 0x280, 0x290, * 0x320, 0x330, 0x340, 0x350 */ port_base = link->io.BasePort1; irq_level = link->irq.AssignedIRQ; DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, USE_FAST_PIO);) chip_init(port_base); host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data)); if (!host) { printk("SYM53C500: Unable to register host, giving up.\n"); goto err_release; } data = (struct sym53c500_data *)host->hostdata; if (irq_level > 0) { if (request_irq(irq_level, SYM53C500_intr, 0, "SYM53C500", host)) { printk("SYM53C500: unable to allocate IRQ %d\n", irq_level); goto err_free_scsi; } DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level)); } else if (irq_level == 0) { DEB(printk("SYM53C500: No interrupts detected\n")); goto err_free_scsi; } else { DEB(printk("SYM53C500: Shouldn't get here!\n")); goto err_free_scsi; } host->unique_id = port_base; host->irq = irq_level; host->io_port = port_base; host->n_io_port = 0x10; host->dma_channel = -1; /* * Note fast_pio is set to USE_FAST_PIO by * default, but can be changed via "sysfs". */ data->fast_pio = USE_FAST_PIO; sprintf(info->node.dev_name, "scsi%d", host->host_no); link->dev = &info->node; info->host = host; if (scsi_add_host(host, NULL)) goto err_free_irq; scsi_scan_host(host); goto out; /* SUCCESS */err_free_irq: free_irq(irq_level, host);err_free_scsi: scsi_host_put(host);err_release: release_region(port_base, 0x10); printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n");out: link->state &= ~DEV_CONFIG_PENDING; return;cs_failed: cs_error(link->handle, last_fn, last_ret); SYM53C500_release(link); return;} /* SYM53C500_config */static intSYM53C500_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; struct scsi_info_t *info = link->priv; DEBUG(1, "SYM53C500_event(0x%06x)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) SYM53C500_release(link); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; SYM53C500_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); /* See earlier comment about manufacturer IDs. */ if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { outb(0x80, link->io.BasePort1 + 0xd); outb(0x24, link->io.BasePort1 + 0x9); outb(0x04, link->io.BasePort1 + 0xd); } /* * If things don't work after a "resume", * this is a good place to start looking. */ SYM53C500_int_host_reset(link->io.BasePort1); } break; } return 0;} /* SYM53C500_event */static voidSYM53C500_detach(dev_link_t *link){ dev_link_t **linkp; DEBUG(0, "SYM53C500_detach(0x%p)\n", link); /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; if (link->state & DEV_CONFIG) SYM53C500_release(link); if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, free bits. */ *linkp = link->next; kfree(link->priv); link->priv = NULL;} /* SYM53C500_detach */static dev_link_t *SYM53C500_attach(void){ struct scsi_info_t *info; client_reg_t client_reg; dev_link_t *link; int i, ret; DEBUG(0, "SYM53C500_attach()\n"); /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.event_handler = &SYM53C500_event; client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); SYM53C500_detach(link); return NULL; } return link;} /* SYM53C500_attach */MODULE_AUTHOR("Bob Tracy <rct@frus.com>");MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");MODULE_LICENSE("GPL");static struct pcmcia_driver sym53c500_cs_driver = { .owner = THIS_MODULE, .drv = { .name = "sym53c500_cs", }, .attach = SYM53C500_attach, .detach = SYM53C500_detach,};static int __initinit_sym53c500_cs(void){ return pcmcia_register_driver(&sym53c500_cs_driver);}static void __exitexit_sym53c500_cs(void){ pcmcia_unregister_driver(&sym53c500_cs_driver);}module_init(init_sym53c500_cs);module_exit(exit_sym53c500_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -