📄 ide-scsi.c
字号:
pc->current_position=pc->buffer; bcount = IDE_MIN (pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ if (drive->using_dma && rq->bh) dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive); SELECT_DRIVE(HWIF(drive), drive); if (IDE_CONTROL_REG) OUT_BYTE (drive->ctl,IDE_CONTROL_REG); OUT_BYTE (dma_ok,IDE_FEATURE_REG); OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG); OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG); if (dma_ok) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); } if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; } else { OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); return idescsi_transfer_pc (drive); }}/* * idescsi_do_request is our request handling function. */static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block){#if IDESCSI_DEBUG_LOG printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);#endif /* IDESCSI_DEBUG_LOG */ if (rq->cmd == IDESCSI_PC_RQ) { return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer); } printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd); idescsi_end_request (0,HWGROUP (drive)); return ide_stopped;}static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive){ MOD_INC_USE_COUNT; return 0;}static void idescsi_ide_release (struct inode *inode, struct file *filp, ide_drive_t *drive){ MOD_DEC_USE_COUNT;}static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];static int idescsi_initialized = 0;static void idescsi_add_settings(ide_drive_t *drive){ idescsi_scsi_t *scsi = drive->driver_data;/* * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function */ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL); ide_add_setting(drive, "log", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->log, NULL);}/* * Driver initialization. */static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id){ DRIVER(drive)->busy++; idescsi_drives[id] = drive; drive->driver_data = scsi; drive->ready_stat = 0; memset (scsi, 0, sizeof (idescsi_scsi_t)); scsi->drive = drive; if (drive->id && (drive->id->config & 0x0060) == 0x20) set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); set_bit(IDESCSI_TRANSFORM, &scsi->transform); clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);#if IDESCSI_DEBUG_LOG set_bit(IDESCSI_LOG_CMD, &scsi->log);#endif /* IDESCSI_DEBUG_LOG */ idescsi_add_settings(drive);}static int idescsi_cleanup (ide_drive_t *drive){ idescsi_scsi_t *scsi = drive->driver_data; if (ide_unregister_subdriver (drive)) return 1; drive->driver_data = NULL; kfree (scsi); return 0;}/* * IDE subdriver functions, registered with ide.c */static ide_driver_t idescsi_driver = { "ide-scsi", /* name */ IDESCSI_VERSION, /* version */ ide_scsi, /* media */ 0, /* busy */ 1, /* supports_dma */ 0, /* supports_dsc_overlap */ idescsi_cleanup, /* cleanup */ idescsi_do_request, /* do_request */ idescsi_end_request, /* end_request */ NULL, /* ioctl */ idescsi_open, /* open */ idescsi_ide_release, /* release */ NULL, /* media_change */ NULL, /* revalidate */ NULL, /* pre_reset */ NULL, /* capacity */ NULL, /* special */ NULL /* proc */};int idescsi_init (void);static ide_module_t idescsi_module = { IDE_DRIVER_MODULE, idescsi_init, &idescsi_driver, NULL};/* * idescsi_init will register the driver for each scsi. */int idescsi_init (void){ ide_drive_t *drive; idescsi_scsi_t *scsi; byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; int i, failed, id; if (idescsi_initialized) return 0; idescsi_initialized = 1; for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++) idescsi_drives[i] = NULL; MOD_INC_USE_COUNT; for (i = 0; media[i] != 255; i++) { failed = 0; while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); continue; } if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) { printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); kfree (scsi); continue; } for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++); idescsi_setup (drive, scsi, id); failed--; } } ide_register_module(&idescsi_module); MOD_DEC_USE_COUNT; return 0;}int idescsi_detect (Scsi_Host_Template *host_template){ struct Scsi_Host *host; int id; int last_lun = 0; host_template->proc_name = "ide-scsi"; host = scsi_register(host_template, 0); if(host == NULL) return 0; for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++) last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun); host->max_id = id; host->max_lun = last_lun + 1; host->can_queue = host->cmd_per_lun * id; return 1;}int idescsi_release (struct Scsi_Host *host){ ide_drive_t *drive; int id; for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) { drive = idescsi_drives[id]; if (drive) DRIVER(drive)->busy--; } return 0;}const char *idescsi_info (struct Scsi_Host *host){ return "SCSI host adapter emulation for IDE ATAPI devices";}int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg){ ide_drive_t *drive = idescsi_drives[dev->id]; idescsi_scsi_t *scsi = drive->driver_data; 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 *) arg); return -EINVAL;}static inline struct buffer_head *idescsi_kmalloc_bh (int count){ struct buffer_head *bh, *bhp, *first_bh; if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL) goto abort; memset (bh, 0, sizeof (struct buffer_head)); bh->b_reqnext = NULL; while (--count) { if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL) goto abort; memset (bh, 0, sizeof (struct buffer_head)); bhp->b_reqnext = bh; bhp = bh; bh->b_reqnext = NULL; } return first_bh;abort: idescsi_free_bh (first_bh); return NULL;}static inline int idescsi_set_direction (idescsi_pc_t *pc){ switch (pc->c[0]) { case READ_6: case READ_10: case READ_12: clear_bit (PC_WRITING, &pc->flags); return 0; case WRITE_6: case WRITE_10: case WRITE_12: set_bit (PC_WRITING, &pc->flags); return 0; default: return 1; }}static inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc_t *pc){ struct buffer_head *bh = NULL, *first_bh = NULL; int segments = pc->scsi_cmd->use_sg; struct scatterlist *sg = pc->scsi_cmd->request_buffer; if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024) return NULL; if (idescsi_set_direction(pc)) return NULL; if (segments) { if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL) return NULL;#if IDESCSI_DEBUG_LOG printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);#endif /* IDESCSI_DEBUG_LOG */ while (segments--) { bh->b_data = sg->address; bh->b_size = sg->length; bh = bh->b_reqnext; sg++; } } else { if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL) return NULL;#if IDESCSI_DEBUG_LOG printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);#endif /* IDESCSI_DEBUG_LOG */ bh->b_data = pc->scsi_cmd->request_buffer; bh->b_size = pc->request_transfer; } return first_bh;}static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd){ idescsi_scsi_t *scsi = drive->driver_data; if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR) return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_TRANSFORM, &scsi->transform);}int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)){ ide_drive_t *drive = idescsi_drives[cmd->target]; idescsi_scsi_t *scsi; struct request *rq = NULL; idescsi_pc_t *pc = NULL; if (!drive) { printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); goto abort; } scsi = drive->driver_data; 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); if (cmd->use_sg) { pc->buffer = NULL; pc->sg = cmd->request_buffer; } else { pc->buffer = cmd->request_buffer; pc->sg = NULL; } pc->b_count = 0; pc->request_transfer = pc->buffer_size = cmd->request_bufflen; pc->scsi_cmd = cmd; pc->done = done; pc->timeout = jiffies + cmd->timeout_per_command; if (should_transform(drive, cmd)) set_bit(PC_TRANSFORM, &pc->flags); idescsi_transform_pc1 (drive, pc); if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number); hexdump(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); hexdump(pc->c, 12); } } ide_init_drive_cmd (rq); rq->buffer = (char *) pc; rq->bh = idescsi_dma_bh (drive, pc); rq->cmd = IDESCSI_PC_RQ; spin_unlock(&io_request_lock); (void) ide_do_drive_cmd (drive, rq, ide_end); spin_lock_irq(&io_request_lock); return 0;abort: if (pc) kfree (pc); if (rq) kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); return 0;}int idescsi_abort (Scsi_Cmnd *cmd){ return SCSI_ABORT_SNOOZE;}int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags){ return SCSI_RESET_SUCCESS;}int idescsi_bios (Disk *disk, kdev_t dev, int *parm){ ide_drive_t *drive = idescsi_drives[disk->device->id]; 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 Scsi_Host_Template idescsi_template = IDESCSI;static int __init init_idescsi_module(void){ idescsi_init(); idescsi_template.module = THIS_MODULE; scsi_register_module (MODULE_SCSI_HA, &idescsi_template); return 0;}static void __exit exit_idescsi_module(void){ ide_drive_t *drive; byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; int i, failed; scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template); for (i = 0; media[i] != 255; i++) { failed = 0; while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL) if (idescsi_cleanup (drive)) { printk ("%s: exit_idescsi_module() called while still busy\n", drive->name); failed++; } } ide_unregister_module(&idescsi_module);}module_init(init_idescsi_module);module_exit(exit_idescsi_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -