ide-scsi.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,160 行 · 第 1/3 页
C
1,160 行
((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16); } else if (test_bit(PC_TIMEDOUT, &pc->flags)) { if (log) printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", drive->name, pc->scsi_cmd->serial_number); pc->scsi_cmd->result = DID_TIME_OUT << 16; } else if (rq->errors >= ERROR_MAX) { pc->scsi_cmd->result = DID_ERROR << 16; if (log) printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); } else if (rq->errors) { if (log) printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); if (!idescsi_check_condition(drive, rq)) /* we started a request sense, so we'll be back, exit for now */ return 0; pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); } else { pc->scsi_cmd->result = DID_OK << 16; idescsi_transform_pc2 (drive, pc); if (log) { printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number); if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) { printk(", rst = "); scsi_buf = pc->scsi_cmd->request_buffer; hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen)); } else printk("\n"); } } 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); idescsi_free_bio(rq->bio); 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->driver_data; 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(); 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 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){ 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); } if (HWGROUP(drive)->handler != NULL) BUG(); /* Set the interrupt routine */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); /* Send the actual packet */ atapi_output_bytes(drive, scsi->pc->c, 12); if (test_bit (PC_DMA_OK, &pc->flags)) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->ide_dma_begin(drive)); } return ide_started;}/* * 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); atapi_feature_t feature; atapi_bcount_t bcount; struct request *rq = pc->rq; 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 && rq->bio) { if (test_bit(PC_WRITING, &pc->flags)) feature.b.dma = !HWIF(drive)->ide_dma_write(drive); else feature.b.dma = !HWIF(drive)->ide_dma_read(drive); } 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)) { if (HWGROUP(drive)->handler != NULL) BUG(); 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 "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, 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 (rq->flags & (REQ_SPECIAL|REQ_SENSE)) { 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;}static void idescsi_add_settings(ide_drive_t *drive){ idescsi_scsi_t *scsi = drive_to_idescsi(drive);/* * 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){ DRIVER(drive)->busy++; drive->ready_stat = 0; 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); DRIVER(drive)->busy--;}static int idescsi_cleanup (ide_drive_t *drive){ struct Scsi_Host *scsihost = drive->driver_data; if (ide_unregister_subdriver(drive)) return 1; /* FIXME?: Are these two statements necessary? */ drive->driver_data = NULL; drive->disk->fops = ide_fops; scsi_remove_host(scsihost); scsi_host_put(scsihost); return 0;}static int idescsi_attach(ide_drive_t *drive);/* * IDE subdriver functions, registered with ide.c */static ide_driver_t idescsi_driver = { .owner = THIS_MODULE, .name = "ide-scsi", .version = IDESCSI_VERSION, .media = ide_scsi, .busy = 0, .supports_dsc_overlap = 0, .attach = idescsi_attach, .cleanup = idescsi_cleanup, .do_request = idescsi_do_request, .end_request = idescsi_end_request, .error = idescsi_atapi_error, .abort = idescsi_atapi_abort, .drives = LIST_HEAD_INIT(idescsi_driver.drives),};static int idescsi_ide_open(struct inode *inode, struct file *filp){ ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; drive->usage++; return 0;}static int idescsi_ide_release(struct inode *inode, struct file *filp){ ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; drive->usage--; 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; return generic_ide_ioctl(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_attach(ide_drive_t *drive);static int idescsi_slave_configure(Scsi_Device * sdp){ /* Configure detected device */ 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 (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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?