📄 aic79xx_osm.c
字号:
* the free directly, but check our * list for extra sanity. */ ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata); if (ahd != NULL) { u_long s; ahd_lock(ahd, &s); ahd_intr_enable(ahd, FALSE); ahd_unlock(ahd, &s); ahd_free(ahd); } } ahd_list_unlock(&l); return (0);}#endif/* * Return a string describing the driver. */static const char *ahd_linux_info(struct Scsi_Host *host){ static char buffer[512]; char ahd_info[256]; char *bp; struct ahd_softc *ahd; bp = &buffer[0]; ahd = *(struct ahd_softc **)host->hostdata; memset(bp, 0, sizeof(buffer)); strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev "); strcat(bp, AIC79XX_DRIVER_VERSION); strcat(bp, "\n"); strcat(bp, " <"); strcat(bp, ahd->description); strcat(bp, ">\n"); strcat(bp, " "); ahd_controller_info(ahd, ahd_info); strcat(bp, ahd_info); strcat(bp, "\n"); return (bp);}/* * Queue an SCB to the controller. */static intahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)){ struct ahd_softc *ahd; struct ahd_linux_device *dev; u_long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; /* * Save the callback on completion function. */ cmd->scsi_done = scsi_done; ahd_midlayer_entrypoint_lock(ahd, &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 (ahd->platform_data->qfrozen != 0 && AHD_DV_CMD(cmd) == 0) { ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); } dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); if (dev == NULL) { ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); ahd_midlayer_entrypoint_unlock(ahd, &flags); printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", ahd_name(ahd)); return (0); } if (cmd->cmd_len > MAX_CDB_LEN) return (-EINVAL); cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); dev->flags |= AHD_DEV_ON_RUN_LIST; ahd_linux_run_device_queues(ahd); } ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static intahd_linux_slave_alloc(Scsi_Device *device){ struct ahd_softc *ahd; ahd = *((struct ahd_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id); return (0);}static intahd_linux_slave_configure(Scsi_Device *device){ struct ahd_softc *ahd; struct ahd_linux_device *dev; u_long flags; ahd = *((struct ahd_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id); ahd_midlayer_entrypoint_lock(ahd, &flags); /* * Since Linux has attached to the device, configure * it so we don't free and allocate the device * structure on every command. */ dev = ahd_linux_get_device(ahd, device->channel, device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { dev->flags &= ~AHD_DEV_UNCONFIGURED; dev->flags |= AHD_DEV_SLAVE_CONFIGURED; dev->scsi_device = device; ahd_linux_device_queue_depth(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0);}static voidahd_linux_slave_destroy(Scsi_Device *device){ struct ahd_softc *ahd; struct ahd_linux_device *dev; u_long flags; ahd = *((struct ahd_softc **)device->host->hostdata); if (bootverbose) printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id); ahd_midlayer_entrypoint_lock(ahd, &flags); dev = ahd_linux_get_device(ahd, 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 & AHD_DEV_SLAVE_CONFIGURED) != 0) { dev->flags |= AHD_DEV_UNCONFIGURED; if (TAILQ_EMPTY(&dev->busyq) && dev->active == 0 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) ahd_linux_free_device(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags);}#else/* * Sets the queue depth for each SCSI device hanging * off the input host adapter. */static voidahd_linux_select_queue_depth(struct Scsi_Host * host, Scsi_Device * scsi_devs){ Scsi_Device *device; Scsi_Device *ldev; struct ahd_softc *ahd; u_long flags; ahd = *((struct ahd_softc **)host->hostdata); ahd_lock(ahd, &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 ahd_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 = ahd_linux_get_device(ahd, device->channel, device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { dev->flags &= ~AHD_DEV_UNCONFIGURED; dev->scsi_device = device; ahd_linux_device_queue_depth(ahd, dev); device->queue_depth = dev->openings + dev->active; if ((dev->flags & (AHD_DEV_Q_BASIC | AHD_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; } } } } ahd_unlock(ahd, &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)ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]){ uint8_t *bh;#elseahd_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 ahd_softc *ahd; ahd = *((struct ahd_softc **)sdev->host->hostdata);#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 (aic79xx_extended != 0) extended = 1; else extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 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 intahd_linux_abort(Scsi_Cmnd *cmd){ struct ahd_softc *ahd; struct ahd_cmd *acmd; struct ahd_cmd *list_acmd; struct ahd_linux_device *dev; struct scb *pending_scb; u_long s; u_int saved_scbptr; u_int active_scbptr; u_int last_phase; u_int cdb_byte; int retval; int was_paused; int paused; int wait; int disconnected; ahd_mode_state saved_modes; pending_scb = NULL; paused = FALSE; wait = FALSE; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; acmd = (struct ahd_cmd *)cmd; printf("%s:%d:%d:%d: Attempting to abort cmd %p:", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun, cmd); for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) printf(" 0x%x", cmd->cmnd[cdb_byte]); printf("\n"); /* * In all versions of Linux, we have to work around * a major flaw in how the mid-layer is locked down * if we are to sleep successfully in our error handler * while allowing our interrupt handler to run. Since * the midlayer acquires either the io_request_lock or * our lock prior to calling us, we must use the * spin_unlock_irq() method for unlocking our lock. * This will force interrupts to be enabled on the * current CPU. Since the EH thread should not have * been running with CPU interrupts disabled other than * by acquiring either the io_request_lock or our own * lock, this *should* be safe. */ ahd_midlayer_entrypoint_lock(ahd, &s); /* * First determine if we currently own this command. * Start by searching the device queue. If not found * there, check the pending_scb list. If not found * at all, and the system wanted us to just abort the * command, return success. */ dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/FALSE); if (dev == NULL) { /* * No target device for this command exists, * so we must not still own the command. */ printf("%s:%d:%d:%d: Is not an active device\n", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun); retval = SUCCESS; goto no_cmd; } TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { if (list_acmd == acmd) break; } if (list_acmd != NULL) { printf("%s:%d:%d:%d: Command found on device queue\n", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun); TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; ahd_linux_queue_cmd_complete(ahd, cmd); retval = SUCCESS; goto done; } /* * See if we can find a matching cmd in the pending list. */ LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { if (pending_scb->io_ctx == cmd) break; } if (pending_scb == NULL) { printf("%s:%d:%d:%d: Command not found\n", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun); goto no_cmd; } if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { /* * We can't queue two recovery actions using the same SCB */ retval = FAILED; goto done; } /* * Ensure that the card doesn't do anything * behind our back. Also make sure that we * didn't "just" miss an interrupt that would * affect this cmd. */ was_paused = ahd_is_paused(ahd); ahd_pause_and_flushwork(ahd); paused = TRUE; if ((pending_scb->flags & SCB_ACTIVE) == 0) { printf("%s:%d:%d:%d: Command already completed\n", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -