X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Fide-scsi.c;h=39b760a2424160c518d3415ef0fc9f4e44843762;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=00a4d60ccf87c2f3001873286ea0775cfc16ae8b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 00a4d60cc..39b760a24 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -45,13 +45,19 @@ #include #include #include +#include +#include +#include #include #include #include -#include "scsi.h" -#include "hosts.h" +#include +#include +#include +#include +#include #include #define IDESCSI_DEBUG_LOG 0 @@ -66,8 +72,8 @@ typedef struct idescsi_pc_s { u8 *current_position; /* Pointer into the above buffer */ struct scatterlist *sg; /* Scatter gather table */ int b_count; /* Bytes transferred from current entry */ - Scsi_Cmnd *scsi_cmd; /* SCSI command */ - void (*done)(Scsi_Cmnd *); /* Scsi completion routine */ + struct scsi_cmnd *scsi_cmd; /* SCSI command */ + void (*done)(struct scsi_cmnd *); /* Scsi completion routine */ unsigned long flags; /* Status/Action flags */ unsigned long timeout; /* Command timeout */ } idescsi_pc_t; @@ -92,14 +98,42 @@ typedef struct idescsi_pc_s { */ #define IDESCSI_LOG_CMD 0 /* Log SCSI commands */ -typedef struct { - ide_drive_t *drive; +typedef struct ide_scsi_obj { + ide_drive_t *drive; + ide_driver_t *driver; + struct gendisk *disk; + struct Scsi_Host *host; + idescsi_pc_t *pc; /* Current packet command */ unsigned long flags; /* Status/Action flags */ unsigned long transform; /* SCSI cmd translation layer */ unsigned long log; /* log flags */ } idescsi_scsi_t; +static DEFINE_MUTEX(idescsi_ref_mutex); + +#define ide_scsi_g(disk) \ + container_of((disk)->private_data, struct ide_scsi_obj, driver) + +static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk) +{ + struct ide_scsi_obj *scsi = NULL; + + mutex_lock(&idescsi_ref_mutex); + scsi = ide_scsi_g(disk); + if (scsi) + scsi_host_get(scsi->host); + mutex_unlock(&idescsi_ref_mutex); + return scsi; +} + +static void ide_scsi_put(struct ide_scsi_obj *scsi) +{ + mutex_lock(&idescsi_ref_mutex); + scsi_host_put(scsi->host); + mutex_unlock(&idescsi_ref_mutex); +} + static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host) { return (idescsi_scsi_t*) (&host[1]); @@ -147,8 +181,21 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne return; } count = min(pc->sg->length - pc->b_count, bcount); - buf = page_address(pc->sg->page) + pc->sg->offset; - atapi_input_bytes (drive, buf + pc->b_count, count); + if (PageHighMem(pc->sg->page)) { + unsigned long flags; + + local_irq_save(flags); + buf = kmap_atomic(pc->sg->page, KM_IRQ0) + + pc->sg->offset; + drive->hwif->atapi_input_bytes(drive, + buf + pc->b_count, count); + kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(pc->sg->page) + pc->sg->offset; + drive->hwif->atapi_input_bytes(drive, + buf + pc->b_count, count); + } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; @@ -169,8 +216,21 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign return; } count = min(pc->sg->length - pc->b_count, bcount); - buf = page_address(pc->sg->page) + pc->sg->offset; - atapi_output_bytes (drive, buf + pc->b_count, count); + if (PageHighMem(pc->sg->page)) { + unsigned long flags; + + local_irq_save(flags); + buf = kmap_atomic(pc->sg->page, KM_IRQ0) + + pc->sg->offset; + drive->hwif->atapi_output_bytes(drive, + buf + pc->b_count, count); + kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); + local_irq_restore(flags); + } else { + buf = page_address(pc->sg->page) + pc->sg->offset; + drive->hwif->atapi_output_bytes(drive, + buf + pc->b_count, count); + } bcount -= count; pc->b_count += count; if (pc->b_count == pc->sg->length) { pc->sg++; @@ -250,17 +310,6 @@ static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc) kfree(atapi_buf); } -static inline void idescsi_free_bio (struct bio *bio) -{ - struct bio *bhp; - - while (bio) { - bhp = bio; - bio = bio->bi_next; - bio_put(bhp); - } -} - static void hexdump(u8 *x, int len) { int i; @@ -283,9 +332,9 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co rq = kmalloc (sizeof (struct request), GFP_ATOMIC); buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC); if (pc == NULL || rq == NULL || buf == NULL) { - if (pc) kfree(pc); - if (rq) kfree(rq); - if (buf) kfree(buf); + kfree(buf); + kfree(rq); + kfree(pc); return -ENOMEM; } memset (pc, 0, sizeof (idescsi_pc_t)); @@ -305,41 +354,37 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co printk ("ide-scsi: %s: queue cmd = ", drive->name); hexdump(pc->c, 6); } + rq->rq_disk = scsi->disk; return ide_do_drive_cmd(drive, rq, ide_preempt); } -ide_startstop_t idescsi_atapi_error (ide_drive_t *drive, const char *msg, byte stat) -{ - struct request *rq; - byte err; - - err = ide_dump_atapi_status(drive, msg, stat); - - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) - return ide_stopped; +static int idescsi_end_request(ide_drive_t *, int, int); +static ide_startstop_t +idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) +{ if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) /* force an abort */ HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); rq->errors++; - DRIVER(drive)->end_request(drive, 0, 0); + + idescsi_end_request(drive, 0, 0); + return ide_stopped; } -ide_startstop_t idescsi_atapi_abort (ide_drive_t *drive, const char *msg) +static ide_startstop_t +idescsi_atapi_abort(ide_drive_t *drive, struct request *rq) { - struct request *rq; - - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) - return ide_stopped; - #if IDESCSI_DEBUG_LOG printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n", ((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number); #endif rq->errors |= ERROR_MAX; - DRIVER(drive)->end_request(drive, 0, 0); + + idescsi_end_request(drive, 0, 0); + return ide_stopped; } @@ -351,6 +396,7 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); struct Scsi_Host *host; u8 *scsi_buf; + int errors = rq->errors; unsigned long flags; if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { @@ -377,11 +423,11 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) 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) { + } else if (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) { + } else if (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)) @@ -404,7 +450,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) 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; @@ -500,7 +545,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) if (pc->sg) idescsi_input_buffers(drive, pc, temp); else - atapi_input_bytes(drive, pc->current_position, temp); + 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; @@ -538,6 +583,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) 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; @@ -559,23 +605,67 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) /* 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); + 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); - (void) (HWIF(drive)->ide_dma_begin(drive)); + 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 = pc->scsi_cmd->request_buffer; + segments = pc->scsi_cmd->use_sg; + + if (segments > hwif->sg_max_nents) + return 1; + + if (!segments) { + hwif->sg_nents = 1; + sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer); + } else { + 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; - struct request *rq = pc->rq; scsi->pc=pc; /* Set the current packet command */ pc->actually_transferred=0; /* We haven't transferred any data yet */ @@ -583,11 +673,10 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) 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); + 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); @@ -653,8 +742,6 @@ static void idescsi_add_settings(ide_drive_t *drive) */ 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); @@ -663,57 +750,81 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) 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) +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; + + ide_unregister_subdriver(drive, scsi->driver); + + ide_unregister_region(g); - if (ide_unregister_subdriver(drive)) - return 1; - - /* FIXME?: Are these two statements necessary? */ drive->driver_data = NULL; - drive->disk->fops = ide_fops; + g->private_data = NULL; + put_disk(g); scsi_remove_host(scsihost); - scsi_host_put(scsihost); - return 0; + ide_scsi_put(scsi); } -static int idescsi_attach(ide_drive_t *drive); +static int ide_scsi_probe(ide_drive_t *); + +#ifdef CONFIG_PROC_FS +static ide_proc_entry_t idescsi_proc[] = { + { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, + { NULL, 0, NULL, NULL } +}; +#else +# define idescsi_proc NULL +#endif -/* - * IDE subdriver functions, registered with ide.c - */ static ide_driver_t idescsi_driver = { - .owner = THIS_MODULE, - .name = "ide-scsi", + .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, - .busy = 0, .supports_dsc_overlap = 0, - .attach = idescsi_attach, - .cleanup = idescsi_cleanup, + .proc = idescsi_proc, .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; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_scsi_obj *scsi; + ide_drive_t *drive; + + if (!(scsi = ide_scsi_get(disk))) + return -ENXIO; + + drive = scsi->drive; + 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; + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ide_scsi_obj *scsi = ide_scsi_g(disk); + ide_drive_t *drive = scsi->drive; + drive->usage--; + + ide_scsi_put(scsi); + return 0; } @@ -721,7 +832,8 @@ 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(bdev, cmd, arg); + 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 = { @@ -731,9 +843,7 @@ static struct block_device_operations idescsi_ops = { .ioctl = idescsi_ide_ioctl, }; -static int idescsi_attach(ide_drive_t *drive); - -static int idescsi_slave_configure(Scsi_Device * sdp) +static int idescsi_slave_configure(struct scsi_device * sdp) { /* Configure detected device */ scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun); @@ -745,7 +855,7 @@ 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 *arg) +static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg) { idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host); @@ -756,86 +866,11 @@ static int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg) 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 put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg); return -EINVAL; } -static inline struct bio *idescsi_kmalloc_bio (int count) -{ - struct bio *bh, *bhp, *first_bh; - - if ((first_bh = bhp = bh = bio_alloc(GFP_ATOMIC, 1)) == NULL) - goto abort; - bio_init(bh); - bh->bi_vcnt = 1; - while (--count) { - if ((bh = bio_alloc(GFP_ATOMIC, 1)) == NULL) - goto abort; - bio_init(bh); - bh->bi_vcnt = 1; - bhp->bi_next = bh; - bhp = bh; - bh->bi_next = NULL; - } - return first_bh; -abort: - idescsi_free_bio (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 bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc) -{ - struct bio *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_bio (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->bi_io_vec[0].bv_page = sg->page; - bh->bi_io_vec[0].bv_len = sg->length; - bh->bi_io_vec[0].bv_offset = sg->offset; - bh->bi_size = sg->length; - bh = bh->bi_next; - sg++; - } - } else { - if ((first_bh = bh = idescsi_kmalloc_bio (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->bi_io_vec[0].bv_page = virt_to_page(pc->scsi_cmd->request_buffer); - bh->bi_io_vec[0].bv_offset = offset_in_page(pc->scsi_cmd->request_buffer); - bh->bi_io_vec[0].bv_len = pc->request_transfer; - bh->bi_size = pc->request_transfer; - } - return first_bh; -} - -static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) +static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); @@ -845,7 +880,7 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) struct gendisk *disk = cmd->request->rq_disk; if (disk) { - struct Scsi_Device_Template **p = disk->private_data; + struct struct scsi_device_Template **p = disk->private_data; if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0) return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); } @@ -853,7 +888,8 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) return test_bit(IDESCSI_TRANSFORM, &scsi->transform); } -static int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +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); @@ -862,7 +898,7 @@ static int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) idescsi_pc_t *pc = NULL; if (!drive) { - printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->device->id); + scmd_printk (KERN_ERR, cmd, "drive not present\n"); goto abort; } scsi = drive_to_idescsi(drive); @@ -905,21 +941,21 @@ static int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ide_init_drive_cmd (rq); rq->special = (char *) pc; - rq->bio = idescsi_dma_bio (drive, pc); rq->flags = REQ_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: - if (pc) kfree (pc); - if (rq) kfree (rq); + kfree (pc); + kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); - return 1; + return 0; } -static int idescsi_eh_abort (Scsi_Cmnd *cmd) +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; @@ -959,7 +995,6 @@ static int idescsi_eh_abort (Scsi_Cmnd *cmd) */ printk (KERN_ERR "ide-scsi: cmd aborted!\n"); - idescsi_free_bio(scsi->pc->rq->bio); if (scsi->pc->rq->flags & REQ_SENSE) kfree(scsi->pc->buffer); kfree(scsi->pc->rq); @@ -978,7 +1013,7 @@ no_drive: return ret; } -static int idescsi_eh_reset (Scsi_Cmnd *cmd) +static int idescsi_eh_reset (struct scsi_cmnd *cmd) { struct request *req; idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); @@ -997,18 +1032,19 @@ static int idescsi_eh_reset (Scsi_Cmnd *cmd) return FAILED; } - spin_lock_irq(&ide_lock); + 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); - idescsi_free_bio(req->bio); + end_that_request_last(req, 0); if (req->flags & REQ_SENSE) kfree(scsi->pc->buffer); kfree(scsi->pc); @@ -1018,22 +1054,21 @@ static int idescsi_eh_reset (Scsi_Cmnd *cmd) /* now nuke the drive queue */ while ((req = elv_next_request(drive->queue))) { blkdev_dequeue_request(req); - end_that_request_last(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_irq(&ide_lock); + 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 { - set_current_state(TASK_UNINTERRUPTIBLE); spin_unlock_irq(cmd->device->host->host_lock); - schedule_timeout(HZ/20); + msleep(50); spin_lock_irq(cmd->device->host->host_lock); } while ( HWGROUP(drive)->handler ); @@ -1044,6 +1079,7 @@ static int idescsi_eh_reset (Scsi_Cmnd *cmd) ret = FAILED; } + spin_unlock_irq(cmd->device->host->host_lock); return ret; } @@ -1061,7 +1097,7 @@ static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev, return 0; } -static Scsi_Host_Template idescsi_template = { +static struct scsi_host_template idescsi_template = { .module = THIS_MODULE, .name = "idescsi", .info = idescsi_info, @@ -1081,12 +1117,13 @@ static Scsi_Host_Template idescsi_template = { .proc_name = "ide-scsi", }; -static int idescsi_attach(ide_drive_t *drive) +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; + 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"); @@ -1097,7 +1134,13 @@ static int idescsi_attach(ide_drive_t *drive) !drive->present || drive->media == ide_disk || !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) - return 1; + return -ENODEV; + + g = alloc_disk(1 << PARTN_BITS); + if (!g) + goto out_host_put; + + ide_init_disk(g, drive); host->max_id = 1; @@ -1113,31 +1156,38 @@ static int idescsi_attach(ide_drive_t *drive) drive->driver_data = host; idescsi = scsihost_to_idescsi(host); idescsi->drive = drive; - err = ide_register_subdriver(drive, &idescsi_driver); + idescsi->driver = &idescsi_driver; + idescsi->host = host; + idescsi->disk = g; + g->private_data = &idescsi->driver; + ide_register_subdriver(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) { - idescsi_setup (drive, idescsi); - drive->disk->fops = &idescsi_ops; - err = scsi_add_host(host, &drive->gendev); - if (!err) { - scsi_scan_host(host); - return 0; - } - /* fall through on error */ - ide_unregister_subdriver(drive); + scsi_scan_host(host); + return 0; } + /* fall through on error */ + ide_unregister_region(g); + ide_unregister_subdriver(drive, &idescsi_driver); + put_disk(g); +out_host_put: scsi_host_put(host); return err; } static int __init init_idescsi_module(void) { - return ide_register_driver(&idescsi_driver); + return driver_register(&idescsi_driver.gen_driver); } static void __exit exit_idescsi_module(void) { - ide_unregister_driver(&idescsi_driver); + driver_unregister(&idescsi_driver.gen_driver); } module_init(init_idescsi_module);