📄 ide-scsi.c
字号:
return 0;}static int idescsi_ide_release(struct inode *inode, struct file *filp){ struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi = ide_scsi_g(disk); ide_scsi_put(scsi); return 0;}static int idescsi_ide_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct block_device *bdev = inode->i_bdev; struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk); return generic_ide_ioctl(scsi->drive, file, bdev, cmd, arg);}static struct block_device_operations idescsi_ops = { .owner = THIS_MODULE, .open = idescsi_ide_open, .release = idescsi_ide_release, .ioctl = idescsi_ide_ioctl,};static int idescsi_slave_configure(struct scsi_device * sdp){ /* Configure detected device */ sdp->use_10_for_rw = 1; sdp->use_10_for_ms = 1; scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun); return 0;}static const char *idescsi_info (struct Scsi_Host *host){ return "SCSI host adapter emulation for IDE ATAPI devices";}static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg){ idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host); if (cmd == SG_SET_TRANSFORM) { if (arg) set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); else clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return 0; } else if (cmd == SG_GET_TRANSFORM) return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg); return -EINVAL;}static int idescsi_queue (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){ struct Scsi_Host *host = cmd->device->host; idescsi_scsi_t *scsi = scsihost_to_idescsi(host); ide_drive_t *drive = scsi->drive; struct request *rq = NULL; idescsi_pc_t *pc = NULL; if (!drive) { scmd_printk (KERN_ERR, cmd, "drive not present\n"); goto abort; } scsi = drive_to_idescsi(drive); pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC); rq = kmalloc (sizeof (struct request), GFP_ATOMIC); if (rq == NULL || pc == NULL) { printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name); goto abort; } memset (pc->c, 0, 12); pc->flags = 0; pc->rq = rq; memcpy (pc->c, cmd->cmnd, cmd->cmd_len); pc->buffer = NULL; pc->sg = scsi_sglist(cmd); pc->sg_cnt = scsi_sg_count(cmd); pc->b_count = 0; pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd); pc->scsi_cmd = cmd; pc->done = done; pc->timeout = jiffies + cmd->timeout_per_command; if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); ide_scsi_hex_dump(cmd->cmnd, cmd->cmd_len); if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) { printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number); ide_scsi_hex_dump(pc->c, 12); } } ide_init_drive_cmd (rq); rq->special = (char *) pc; rq->cmd_type = REQ_TYPE_SPECIAL; spin_unlock_irq(host->host_lock); rq->rq_disk = scsi->disk; (void) ide_do_drive_cmd (drive, rq, ide_end); spin_lock_irq(host->host_lock); return 0;abort: kfree (pc); kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); return 0;}static int idescsi_eh_abort (struct scsi_cmnd *cmd){ idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); ide_drive_t *drive = scsi->drive; int busy; int ret = FAILED; /* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number); if (!drive) { printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n"); WARN_ON(1); goto no_drive; } /* First give it some more time, how much is "right" is hard to say :-( */ busy = ide_wait_not_busy(HWIF(drive), 100); /* FIXME - uses mdelay which causes latency? */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":""); spin_lock_irq(&ide_lock); /* If there is no pc running we're done (our interrupt took care of it) */ if (!scsi->pc) { ret = SUCCESS; goto ide_unlock; } /* It's somewhere in flight. Does ide subsystem agree? */ if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy && elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) { /* * FIXME - not sure this condition can ever occur */ printk (KERN_ERR "ide-scsi: cmd aborted!\n"); if (blk_sense_request(scsi->pc->rq)) kfree(scsi->pc->buffer); kfree(scsi->pc->rq); kfree(scsi->pc); scsi->pc = NULL; ret = SUCCESS; }ide_unlock: spin_unlock_irq(&ide_lock);no_drive: if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed"); return ret;}static int idescsi_eh_reset (struct scsi_cmnd *cmd){ struct request *req; idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); ide_drive_t *drive = scsi->drive; int ready = 0; int ret = SUCCESS; /* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number); if (!drive) { printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n"); WARN_ON(1); return FAILED; } spin_lock_irq(cmd->device->host->host_lock); spin_lock(&ide_lock); if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) { printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n"); spin_unlock(&ide_lock); spin_unlock_irq(cmd->device->host->host_lock); return FAILED; } /* kill current request */ blkdev_dequeue_request(req); end_that_request_last(req, 0); if (blk_sense_request(req)) kfree(scsi->pc->buffer); kfree(scsi->pc); scsi->pc = NULL; kfree(req); /* now nuke the drive queue */ while ((req = elv_next_request(drive->queue))) { blkdev_dequeue_request(req); end_that_request_last(req, 0); } HWGROUP(drive)->rq = NULL; HWGROUP(drive)->handler = NULL; HWGROUP(drive)->busy = 1; /* will set this to zero when ide reset finished */ spin_unlock(&ide_lock); ide_do_reset(drive); /* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */ do { spin_unlock_irq(cmd->device->host->host_lock); msleep(50); spin_lock_irq(cmd->device->host->host_lock); } while ( HWGROUP(drive)->handler ); ready = drive_is_ready(drive); HWGROUP(drive)->busy--; if (!ready) { printk (KERN_ERR "ide-scsi: reset failed!\n"); ret = FAILED; } spin_unlock_irq(cmd->device->host->host_lock); return ret;}static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *parm){ idescsi_scsi_t *idescsi = scsihost_to_idescsi(sdev->host); ide_drive_t *drive = idescsi->drive; if (drive->bios_cyl && drive->bios_head && drive->bios_sect) { parm[0] = drive->bios_head; parm[1] = drive->bios_sect; parm[2] = drive->bios_cyl; } return 0;}static struct scsi_host_template idescsi_template = { .module = THIS_MODULE, .name = "idescsi", .info = idescsi_info, .slave_configure = idescsi_slave_configure, .ioctl = idescsi_ioctl, .queuecommand = idescsi_queue, .eh_abort_handler = idescsi_eh_abort, .eh_host_reset_handler = idescsi_eh_reset, .bios_param = idescsi_bios, .can_queue = 40, .this_id = -1, .sg_tablesize = 256, .cmd_per_lun = 5, .max_sectors = 128, .use_clustering = DISABLE_CLUSTERING, .emulated = 1, .proc_name = "ide-scsi",};static int ide_scsi_probe(ide_drive_t *drive){ idescsi_scsi_t *idescsi; struct Scsi_Host *host; struct gendisk *g; static int warned; int err = -ENOMEM; if (!warned && drive->media == ide_cdrom) { printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n"); warned = 1; } if (idescsi_nocd && drive->media == ide_cdrom) return -ENODEV; if (!strstr("ide-scsi", drive->driver_req) || !drive->present || drive->media == ide_disk || !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) return -ENODEV; g = alloc_disk(1 << PARTN_BITS); if (!g) goto out_host_put; ide_init_disk(g, drive); host->max_id = 1;#if IDESCSI_DEBUG_LOG if (drive->id->last_lun) printk(KERN_NOTICE "%s: id->last_lun=%u\n", drive->name, drive->id->last_lun);#endif if ((drive->id->last_lun & 0x7) != 7) host->max_lun = (drive->id->last_lun & 0x7) + 1; else host->max_lun = 1; drive->driver_data = host; idescsi = scsihost_to_idescsi(host); idescsi->drive = drive; idescsi->driver = &idescsi_driver; idescsi->host = host; idescsi->disk = g; g->private_data = &idescsi->driver; ide_proc_register_driver(drive, &idescsi_driver); err = 0; idescsi_setup(drive, idescsi); g->fops = &idescsi_ops; ide_register_region(g); err = scsi_add_host(host, &drive->gendev); if (!err) { scsi_scan_host(host); return 0; } /* fall through on error */ ide_unregister_region(g); ide_proc_unregister_driver(drive, &idescsi_driver); put_disk(g);out_host_put: scsi_host_put(host); return err;}static int __init init_idescsi_module(void){ return driver_register(&idescsi_driver.gen_driver);}static void __exit exit_idescsi_module(void){ driver_unregister(&idescsi_driver.gen_driver);}module_param(idescsi_nocd, int, 0600);MODULE_PARM_DESC(idescsi_nocd, "Disable handling of CD-ROMs so they may be driven by ide-cd");module_init(init_idescsi_module);module_exit(exit_idescsi_module);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -