📄 ide-scsi.c
字号:
} else { pc->scsi_cmd->result = DID_OK << 16; } host = pc->scsi_cmd->device->host; spin_lock_irqsave(host->host_lock, flags); pc->done(pc->scsi_cmd); spin_unlock_irqrestore(host->host_lock, flags); kfree(pc); kfree(rq); scsi->pc = NULL; return 0;}static inline unsigned long get_timeout(idescsi_pc_t *pc){ return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);}static int idescsi_expiry(ide_drive_t *drive){ idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_pc_t *pc = scsi->pc;#if IDESCSI_DEBUG_LOG printk(KERN_WARNING "idescsi_expiry called for %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies);#endif set_bit(PC_TIMEDOUT, &pc->flags); return 0; /* we do not want the ide subsystem to retry */}/* * Our interrupt handler. */static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive){ idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_pc_t *pc=scsi->pc; struct request *rq = pc->rq; atapi_bcount_t bcount; atapi_status_t status; atapi_ireason_t ireason; atapi_feature_t feature; unsigned int temp;#if IDESCSI_DEBUG_LOG printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");#endif /* IDESCSI_DEBUG_LOG */ if (test_bit(PC_TIMEDOUT, &pc->flags)){#if IDESCSI_DEBUG_LOG printk(KERN_WARNING "idescsi_pc_intr: got timed out packet %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies);#endif /* end this request now - scsi should retry it*/ idescsi_end_request (drive, 1, 0); return ide_stopped; } if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {#if IDESCSI_DEBUG_LOG printk ("ide-scsi: %s: DMA complete\n", drive->name);#endif /* IDESCSI_DEBUG_LOG */ pc->actually_transferred=pc->request_transfer; (void) HWIF(drive)->ide_dma_end(drive); } feature.all = 0; /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!status.b.drq) { /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); local_irq_enable_in_hardirq(); if (status.b.check) rq->errors++; idescsi_end_request (drive, 1, 0); return ide_stopped; } bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); if (ireason.b.cod) { printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n"); return ide_do_reset (drive); } if (ireason.b.io) { temp = pc->actually_transferred + bcount.all; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-scsi: The scsi wants to " "send us more data than expected " "- discarding data\n"); temp = pc->buffer_size - pc->actually_transferred; if (temp) { clear_bit(PC_WRITING, &pc->flags); if (pc->sg) idescsi_input_buffers(drive, pc, temp); else drive->hwif->atapi_input_bytes(drive, pc->current_position, temp); printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all); } pc->actually_transferred += temp; pc->current_position += temp; idescsi_discard_data(drive, bcount.all - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; }#if IDESCSI_DEBUG_LOG printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");#endif /* IDESCSI_DEBUG_LOG */ } } if (ireason.b.io) { clear_bit(PC_WRITING, &pc->flags); if (pc->sg) idescsi_input_buffers(drive, pc, bcount.all); else HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); } else { set_bit(PC_WRITING, &pc->flags); if (pc->sg) idescsi_output_buffers (drive, pc, bcount.all); else HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); } /* Update the current position */ pc->actually_transferred += bcount.all; pc->current_position += bcount.all; /* And set the interrupt handler again */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started;}static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive){ ide_hwif_t *hwif = drive->hwif; idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_pc_t *pc = scsi->pc; atapi_ireason_t ireason; ide_startstop_t startstop; if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk(KERN_ERR "ide-scsi: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset (drive); } BUG_ON(HWGROUP(drive)->handler != NULL); /* Set the interrupt routine */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); /* Send the actual packet */ drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12); if (test_bit (PC_DMA_OK, &pc->flags)) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); hwif->dma_start(drive); } return ide_started;}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 int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc){ ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg, *scsi_sg; int segments; if (!pc->request_transfer || pc->request_transfer % 1024) return 1; if (idescsi_set_direction(pc)) return 1; sg = hwif->sg_table; scsi_sg = scsi_sglist(pc->scsi_cmd); segments = scsi_sg_count(pc->scsi_cmd); if (segments > hwif->sg_max_nents) return 1; hwif->sg_nents = segments; memcpy(sg, scsi_sg, sizeof(*sg) * segments); return 0;}/* * Issue a packet command */static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc){ idescsi_scsi_t *scsi = drive_to_idescsi(drive); ide_hwif_t *hwif = drive->hwif; atapi_feature_t feature; atapi_bcount_t bcount; scsi->pc=pc; /* Set the current packet command */ pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; bcount.all = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ feature.all = 0; if (drive->using_dma && !idescsi_map_sg(drive, pc)) { hwif->sg_mapped = 1; feature.b.dma = !hwif->dma_setup(drive); hwif->sg_mapped = 0; } SELECT_DRIVE(drive); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); if (feature.b.dma) set_bit(PC_DMA_OK, &pc->flags); if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &idescsi_transfer_pc, get_timeout(pc), idescsi_expiry); /* Issue the packet command */ HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); return ide_started; } else { /* Issue the packet command */ HWIF(drive)->OUTB(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, sector_t block){#if IDESCSI_DEBUG_LOG printk (KERN_INFO "dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,rq->cmd[0],rq->errors); printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);#endif /* IDESCSI_DEBUG_LOG */ if (blk_sense_request(rq) || blk_special_request(rq)) { return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special); } blk_dump_rq_flags(rq, "ide-scsi: unsup command"); idescsi_end_request (drive, 0, 0); return ide_stopped;}#ifdef CONFIG_IDE_PROC_FSstatic void idescsi_add_settings(ide_drive_t *drive){ idescsi_scsi_t *scsi = drive_to_idescsi(drive);/* * drive setting name read/write data type min max mul_factor div_factor data pointer set function */ ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "transform", SETTING_RW, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL); ide_add_setting(drive, "log", SETTING_RW, TYPE_INT, 0, 1, 1, 1, &scsi->log, NULL);}#elsestatic inline void idescsi_add_settings(ide_drive_t *drive) { ; }#endif/* * Driver initialization. */static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi){ if (drive->id && (drive->id->config & 0x0060) == 0x20) set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); 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 void ide_scsi_remove(ide_drive_t *drive){ struct Scsi_Host *scsihost = drive->driver_data; struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost); struct gendisk *g = scsi->disk; scsi_remove_host(scsihost); ide_proc_unregister_driver(drive, scsi->driver); ide_unregister_region(g); drive->driver_data = NULL; g->private_data = NULL; put_disk(g); ide_scsi_put(scsi);}static int ide_scsi_probe(ide_drive_t *);#ifdef CONFIG_IDE_PROC_FSstatic ide_proc_entry_t idescsi_proc[] = { { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, { NULL, 0, NULL, NULL }};#endifstatic ide_driver_t idescsi_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-scsi", .bus = &ide_bus_type, }, .probe = ide_scsi_probe, .remove = ide_scsi_remove, .version = IDESCSI_VERSION, .media = ide_scsi, .supports_dsc_overlap = 0, .do_request = idescsi_do_request, .end_request = idescsi_end_request, .error = idescsi_atapi_error, .abort = idescsi_atapi_abort,#ifdef CONFIG_IDE_PROC_FS .proc = idescsi_proc,#endif};static int idescsi_ide_open(struct inode *inode, struct file *filp){ struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_scsi_obj *scsi; if (!(scsi = ide_scsi_get(disk))) return -ENXIO;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -