📄 aic7xxx_osm.c
字号:
/* * Initialize our softc list lock prior to * probing for any adapters. */ ahc_list_lockinit(); found = ahc_linux_pci_init(); if (!ahc_linux_eisa_init()) found++; /* * Register with the SCSI layer all * controllers we've found. */ TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc_linux_register_host(ahc, template) == 0) found++; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) spin_lock_irq(&io_request_lock);#endif aic7xxx_detect_complete++; return (found);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)/* * Free the passed in Scsi_Host memory structures prior to unloading the * module. */intahc_linux_release(struct Scsi_Host * host){ struct ahc_softc *ahc; u_long l; ahc_list_lock(&l); if (host != NULL) { /* * We should be able to just perform * the free directly, but check our * list for extra sanity. */ ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata); if (ahc != NULL) { u_long s; ahc_lock(ahc, &s); ahc_intr_enable(ahc, FALSE); ahc_unlock(ahc, &s); ahc_free(ahc); } } ahc_list_unlock(&l); return (0);}#endif/* * Return a string describing the driver. */static const char *ahc_linux_info(struct Scsi_Host *host){ static char buffer[512]; char ahc_info[256]; char *bp; struct ahc_softc *ahc; bp = &buffer[0]; ahc = *(struct ahc_softc **)host->hostdata; memset(bp, 0, sizeof(buffer)); strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev "); strcat(bp, AIC7XXX_DRIVER_VERSION); strcat(bp, "\n"); strcat(bp, " <"); strcat(bp, ahc->description); strcat(bp, ">\n"); strcat(bp, " "); ahc_controller_info(ahc, ahc_info); strcat(bp, ahc_info); strcat(bp, "\n"); return (bp);}/* * Queue an SCB to the controller. */static intahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)){ struct ahc_softc *ahc; struct ahc_linux_device *dev; u_long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; /* * Save the callback on completion function. */ cmd->scsi_done = scsi_done; ahc_midlayer_entrypoint_lock(ahc, &flags); /* * Close the race of a command that was in the process of * being queued to us just as our simq was frozen. Let * DV commands through so long as we are only frozen to * perform DV. */ if (ahc->platform_data->qfrozen != 0 && AHC_DV_CMD(cmd) == 0) { ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahc_linux_queue_cmd_complete(ahc, cmd); ahc_schedule_completeq(ahc); ahc_midlayer_entrypoint_unlock(ahc, &flags); return (0); } dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); if (dev == NULL) { ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahc_linux_queue_cmd_complete(ahc, cmd); ahc_schedule_completeq(ahc); ahc_midlayer_entrypoint_unlock(ahc, &flags); printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n", ahc_name(ahc)); return (0); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); dev->flags |= AHC_DEV_ON_RUN_LIST; ahc_linux_run_device_queues(ahc); } ahc_midlayer_entrypoint_unlock(ahc, &flags); return (0);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static intahc_linux_slave_alloc(Scsi_Device *device){ struct ahc_softc *ahc; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id); return (0);}static intahc_linux_slave_configure(Scsi_Device *device){ struct ahc_softc *ahc; struct ahc_linux_device *dev; u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id); ahc_midlayer_entrypoint_lock(ahc, &flags); /* * Since Linux has attached to the device, configure * it so we don't free and allocate the device * structure on every command. */ dev = ahc_linux_get_device(ahc, device->channel, device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { dev->flags &= ~AHC_DEV_UNCONFIGURED; dev->scsi_device = device; ahc_linux_device_queue_depth(ahc, dev); } ahc_midlayer_entrypoint_unlock(ahc, &flags); return (0);}static voidahc_linux_slave_destroy(Scsi_Device *device){ struct ahc_softc *ahc; struct ahc_linux_device *dev; u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id); ahc_midlayer_entrypoint_lock(ahc, &flags); dev = ahc_linux_get_device(ahc, device->channel, device->id, device->lun, /*alloc*/FALSE); /* * Filter out "silly" deletions of real devices by only * deleting devices that have had slave_configure() * called on them. All other devices that have not * been configured will automatically be deleted by * the refcounting process. */ if (dev != NULL && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) { dev->flags |= AHC_DEV_UNCONFIGURED; if (TAILQ_EMPTY(&dev->busyq) && dev->active == 0 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) ahc_linux_free_device(ahc, dev); } ahc_midlayer_entrypoint_unlock(ahc, &flags);}#else/* * Sets the queue depth for each SCSI device hanging * off the input host adapter. */static voidahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs){ Scsi_Device *device; Scsi_Device *ldev; struct ahc_softc *ahc; u_long flags; ahc = *((struct ahc_softc **)host->hostdata); ahc_lock(ahc, &flags); for (device = scsi_devs; device != NULL; device = device->next) { /* * Watch out for duplicate devices. This works around * some quirks in how the SCSI scanning code does its * device management. */ for (ldev = scsi_devs; ldev != device; ldev = ldev->next) { if (ldev->host == device->host && ldev->channel == device->channel && ldev->id == device->id && ldev->lun == device->lun) break; } /* Skip duplicate. */ if (ldev != device) continue; if (device->host == host) { struct ahc_linux_device *dev; /* * Since Linux has attached to the device, configure * it so we don't free and allocate the device * structure on every command. */ dev = ahc_linux_get_device(ahc, device->channel, device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { dev->flags &= ~AHC_DEV_UNCONFIGURED; dev->scsi_device = device; ahc_linux_device_queue_depth(ahc, dev); device->queue_depth = dev->openings + dev->active; if ((dev->flags & (AHC_DEV_Q_BASIC | AHC_DEV_Q_TAGGED)) == 0) { /* * We allow the OS to queue 2 untagged * transactions to us at any time even * though we can only execute them * serially on the controller/device. * This should remove some latency. */ device->queue_depth = 2; } } } } ahc_unlock(ahc, &flags);}#endif#if defined(__i386__)/* * Return the disk geometry for the given SCSI device. */static int#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]){ uint8_t *bh;#elseahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]){ struct scsi_device *sdev = disk->device; u_long capacity = disk->capacity; struct buffer_head *bh;#endif int heads; int sectors; int cylinders; int ret; int extended; struct ahc_softc *ahc; u_int channel; ahc = *((struct ahc_softc **)sdev->host->hostdata); channel = sdev->channel;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) bh = scsi_bios_ptable(bdev);#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17) bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));#else bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);#endif if (bh) { ret = scsi_partsize(bh, capacity, &geom[2], &geom[0], &geom[1]);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) kfree(bh);#else brelse(bh);#endif if (ret != -1) return (ret); } heads = 64; sectors = 32; cylinders = aic_sector_div(capacity, heads, sectors); if (aic7xxx_extended != 0) extended = 1; else if (channel == 0) extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; else extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; if (extended && cylinders >= 1024) { heads = 255; sectors = 63; cylinders = aic_sector_div(capacity, heads, sectors); } geom[0] = heads; geom[1] = sectors; geom[2] = cylinders; return (0);}#endif/* * Abort the current SCSI command(s). */static intahc_linux_abort(Scsi_Cmnd *cmd){ int error; error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) printf("aic7xxx_abort returns 0x%x\n", error); return (error);}/* * Attempt to send a target reset message to the device that timed out. */static intahc_linux_dev_reset(Scsi_Cmnd *cmd){ int error; error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) printf("aic7xxx_dev_reset returns 0x%x\n", error); return (error);}/* * Reset the SCSI bus. */static intahc_linux_bus_reset(Scsi_Cmnd *cmd){ struct ahc_softc *ahc; u_long s; int found; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; ahc_midlayer_entrypoint_lock(ahc, &s); found = ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate reset*/TRUE); ahc_linux_run_complete_queue(ahc); ahc_midlayer_entrypoint_unlock(ahc, &s); if (bootverbose) printf("%s: SCSI bus reset delivered. " "%d SCBs aborted.\n", ahc_name(ahc), found); return SUCCESS;}Scsi_Host_Template aic7xxx_driver_template = { .module = THIS_MODULE, .name = "aic7xxx", .proc_info = ahc_linux_proc_info, .info = ahc_linux_info, .queuecommand = ahc_linux_queue, .eh_abort_handler = ahc_linux_abort, .eh_device_reset_handler = ahc_linux_dev_reset, .eh_bus_reset_handler = ahc_linux_bus_reset,#if defined(__i386__) .bios_param = ahc_linux_biosparam,#endif .can_queue = AHC_MAX_QUEUE, .this_id = -1, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .slave_destroy = ahc_linux_slave_destroy,};/**************************** Tasklet Handler *********************************//* * In 2.4.X and above, this routine is called from a tasklet, * so we must re-acquire our lock prior to executing this code. * In all prior kernels, ahc_schedule_runq() calls this routine * directly and ahc_schedule_runq() is called with our lock held. */static voidahc_runq_tasklet(unsigned long data){ struct ahc_softc* ahc; struct ahc_linux_device *dev;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) u_long flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -