Commit 7cfdf2cc authored by Adam J. Richter's avatar Adam J. Richter Committed by James Bottomley

| The following changes to ide-scsi.c are a recovery of the

| changes that I had in ide-scsi.c in the stock kernel's before
| Martin Dalecki's IDE tree was reverted and a few other changes.
| 
|         The principal change is that each ATAPI device is a Scsi_host
| (which reflects reality), instead of having one fake Scsi_Host with
| that appears to have all of the ATAPI devices on one bus regardless of
| actual hardware topology.  This way it is much easier for software to
| tell that, for example, a scsi copy command will not work between two
| ATAPI devices.  More importantly, hot plugging should theoretically
| work now, since Scsi_hosts are allocated and deallocated as ATAPI
| devices are added or removed. 
| 
|         This change eliminates the idescsi_drives[] array and the
| ide_driver_t.id field that was used to index it.
| 
|         The idescsi_scsi_t data structure is now allocated at
| the end of the struct Scsi_Host rather than being a separate
| memory allocation.  The calculation of various private pointers
| are changed slightly as a result.
| 
|         Other minor nits include making all global routines
| static and adding some missing error branches in
| init_idescsi_module.
| 
|         I've verified that I can at least read raw data
| from a DVD-ROM with with this change.
| 
|         When I unload this ide-scsi module, the stock ide-scsi module
| or the stock ide-cd modules in 2.5.56, I get what appears to be the
| same kernel bad memory reference, apparently due to some generic
| device device added to drivers/ide/ide.c.  It does not appear to
| be due to this patch.
| 
|         The patch is a net deletion of one line.
|
parent fdb6c00f
...@@ -96,9 +96,18 @@ typedef struct { ...@@ -96,9 +96,18 @@ typedef struct {
unsigned long flags; /* Status/Action flags */ unsigned long flags; /* Status/Action flags */
unsigned long transform; /* SCSI cmd translation layer */ unsigned long transform; /* SCSI cmd translation layer */
unsigned long log; /* log flags */ unsigned long log; /* log flags */
int id;
} idescsi_scsi_t; } idescsi_scsi_t;
static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
{
return (idescsi_scsi_t*) (&host[1]);
}
static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive)
{
return scsihost_to_idescsi(ide_drive->driver_data);
}
/* /*
* Per ATAPI device status bits. * Per ATAPI device status bits.
*/ */
...@@ -262,7 +271,7 @@ static void hexdump(u8 *x, int len) ...@@ -262,7 +271,7 @@ static void hexdump(u8 *x, int len)
static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command) static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
idescsi_pc_t *pc; idescsi_pc_t *pc;
struct request *rq; struct request *rq;
u8 *buf; u8 *buf;
...@@ -299,7 +308,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co ...@@ -299,7 +308,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co
static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
idescsi_pc_t *pc = (idescsi_pc_t *) rq->special; idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
...@@ -369,7 +378,7 @@ static inline unsigned long get_timeout(idescsi_pc_t *pc) ...@@ -369,7 +378,7 @@ static inline unsigned long get_timeout(idescsi_pc_t *pc)
*/ */
static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
idescsi_pc_t *pc=scsi->pc; idescsi_pc_t *pc=scsi->pc;
struct request *rq = pc->rq; struct request *rq = pc->rq;
atapi_bcount_t bcount; atapi_bcount_t bcount;
...@@ -463,7 +472,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) ...@@ -463,7 +472,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
idescsi_pc_t *pc = scsi->pc; idescsi_pc_t *pc = scsi->pc;
atapi_ireason_t ireason; atapi_ireason_t ireason;
ide_startstop_t startstop; ide_startstop_t startstop;
...@@ -493,7 +502,7 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) ...@@ -493,7 +502,7 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
*/ */
static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
atapi_feature_t feature; atapi_feature_t feature;
atapi_bcount_t bcount; atapi_bcount_t bcount;
struct request *rq = pc->rq; struct request *rq = pc->rq;
...@@ -555,11 +564,9 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r ...@@ -555,11 +564,9 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
return ide_stopped; return ide_stopped;
} }
static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
static void idescsi_add_settings(ide_drive_t *drive) static void idescsi_add_settings(ide_drive_t *drive)
{ {
idescsi_scsi_t *scsi = drive->driver_data; 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 * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
...@@ -574,15 +581,10 @@ static void idescsi_add_settings(ide_drive_t *drive) ...@@ -574,15 +581,10 @@ static void idescsi_add_settings(ide_drive_t *drive)
/* /*
* Driver initialization. * Driver initialization.
*/ */
static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id) static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
{ {
DRIVER(drive)->busy++; DRIVER(drive)->busy++;
idescsi_drives[id] = drive;
drive->driver_data = scsi;
drive->ready_stat = 0; drive->ready_stat = 0;
memset (scsi, 0, sizeof (idescsi_scsi_t));
scsi->drive = drive;
scsi->id = id;
if (drive->id && (drive->id->config & 0x0060) == 0x20) if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
set_bit(IDESCSI_TRANSFORM, &scsi->transform); set_bit(IDESCSI_TRANSFORM, &scsi->transform);
...@@ -596,13 +598,17 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id) ...@@ -596,13 +598,17 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
static int idescsi_cleanup (ide_drive_t *drive) static int idescsi_cleanup (ide_drive_t *drive)
{ {
idescsi_scsi_t *scsi = drive->driver_data; struct Scsi_Host *scsihost = drive->driver_data;
if (ide_unregister_subdriver(drive)) if (ide_unregister_subdriver(drive))
return 1; return 1;
/* FIXME?: Are these two statements necessary? */
drive->driver_data = NULL; drive->driver_data = NULL;
drive->disk->fops = ide_fops; drive->disk->fops = ide_fops;
kfree(scsi);
scsi_remove_host(scsihost);
scsi_unregister(scsihost);
return 0; return 0;
} }
...@@ -654,52 +660,23 @@ static struct block_device_operations idescsi_ops = { ...@@ -654,52 +660,23 @@ static struct block_device_operations idescsi_ops = {
.ioctl = idescsi_ide_ioctl, .ioctl = idescsi_ide_ioctl,
}; };
static int idescsi_attach(ide_drive_t *drive) static int idescsi_attach(ide_drive_t *drive);
{
idescsi_scsi_t *scsi;
int id;
if (!strstr("ide-scsi", drive->driver_req))
goto failed;
if (!drive->present)
goto failed;
/* we accept everything except ide-disk */
if (drive->media == ide_disk)
goto failed;
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);
goto failed;
}
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);
goto failed;
}
for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
;
idescsi_setup (drive, scsi, id);
drive->disk->fops = &idescsi_ops;
return 0;
failed:
return 1;
}
int idescsi_slave_configure(Scsi_Device * sdp) static int idescsi_slave_configure(Scsi_Device * sdp)
{ {
/* Configure detected device */ /* Configure detected device */
scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun); scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
return 0; return 0;
} }
const char *idescsi_info (struct Scsi_Host *host) static const char *idescsi_info (struct Scsi_Host *host)
{ {
return "SCSI host adapter emulation for IDE ATAPI devices"; return "SCSI host adapter emulation for IDE ATAPI devices";
} }
int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg) static int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{ {
ide_drive_t *drive = idescsi_drives[dev->id]; idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host);
idescsi_scsi_t *scsi = drive->driver_data;
if (cmd == SG_SET_TRANSFORM) { if (cmd == SG_SET_TRANSFORM) {
if (arg) if (arg)
...@@ -789,7 +766,7 @@ static inline struct bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc) ...@@ -789,7 +766,7 @@ static inline struct bio *idescsi_dma_bio(ide_drive_t *drive, idescsi_pc_t *pc)
static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
{ {
idescsi_scsi_t *scsi = drive->driver_data; idescsi_scsi_t *scsi = drive_to_idescsi(drive);
struct gendisk *disk = cmd->request->rq_disk; struct gendisk *disk = cmd->request->rq_disk;
if (disk) { if (disk) {
...@@ -800,10 +777,10 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) ...@@ -800,10 +777,10 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd)
return test_bit(IDESCSI_TRANSFORM, &scsi->transform); return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
} }
int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) static int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{ {
ide_drive_t *drive = idescsi_drives[cmd->target]; idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->host);
idescsi_scsi_t *scsi; ide_drive_t *drive = scsi->drive;
struct request *rq = NULL; struct request *rq = NULL;
idescsi_pc_t *pc = NULL; idescsi_pc_t *pc = NULL;
...@@ -811,7 +788,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ...@@ -811,7 +788,7 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target); printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
goto abort; goto abort;
} }
scsi = drive->driver_data; scsi = drive_to_idescsi(drive);
pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC); pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
rq = kmalloc (sizeof (struct request), GFP_ATOMIC); rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
if (rq == NULL || pc == NULL) { if (rq == NULL || pc == NULL) {
...@@ -865,43 +842,43 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ...@@ -865,43 +842,43 @@ int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
return 1; return 1;
} }
int idescsi_abort (Scsi_Cmnd *cmd) static int idescsi_abort (Scsi_Cmnd *cmd)
{ {
int countdown = 8; int countdown = 8;
unsigned long flags; unsigned long flags;
ide_drive_t *drive = idescsi_drives[cmd->target]; idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->host);
idescsi_scsi_t *scsi; ide_drive_t *drive = scsi->drive;
printk (KERN_ERR "ide-scsi: abort called for %lu\n", cmd->serial_number); printk (KERN_ERR "ide-scsi: abort called for %lu\n", cmd->serial_number);
if (drive && (scsi = drive->driver_data)) while (countdown--) {
while (countdown--) { /* is cmd active?
/* is cmd active? * need to lock so this stuff doesn't change under us */
* need to lock so this stuff doesn't change under us */ spin_lock_irqsave(&ide_lock, flags);
spin_lock_irqsave(&ide_lock, flags); if (scsi->pc && scsi->pc->scsi_cmd &&
if (scsi->pc && scsi->pc->scsi_cmd && scsi->pc->scsi_cmd->serial_number == cmd->serial_number) {
scsi->pc->scsi_cmd->serial_number == cmd->serial_number) { /* yep - let's give it some more time -
/* yep - let's give it some more time - * we can do that, we're in _our_ error kernel thread */
* we can do that, we're in _our_ error kernel thread */ spin_unlock_irqrestore(&ide_lock, flags);
spin_unlock_irqrestore(&ide_lock, flags); scsi_sleep(HZ);
scsi_sleep(HZ); continue;
continue; }
} /* no, but is it queued in the ide subsystem? */
/* no, but is it queued in the ide subsystem? */ if (elv_queue_empty(&drive->queue)) {
if (elv_queue_empty(&drive->queue)) {
spin_unlock_irqrestore(&ide_lock, flags);
return SUCCESS;
}
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
schedule_timeout(HZ/10); return SUCCESS;
} }
spin_unlock_irqrestore(&ide_lock, flags);
schedule_timeout(HZ/10);
}
return FAILED; return FAILED;
} }
int idescsi_reset (Scsi_Cmnd *cmd) static int idescsi_reset (Scsi_Cmnd *cmd)
{ {
unsigned long flags; unsigned long flags;
struct request *req; struct request *req;
ide_drive_t *drive = idescsi_drives[cmd->target]; idescsi_scsi_t *idescsi = scsihost_to_idescsi(cmd->host);
ide_drive_t *drive = idescsi->drive;
printk (KERN_ERR "ide-scsi: reset called for %lu\n", cmd->serial_number); printk (KERN_ERR "ide-scsi: reset called for %lu\n", cmd->serial_number);
/* first null the handler for the drive and let any process /* first null the handler for the drive and let any process
...@@ -919,7 +896,8 @@ int idescsi_reset (Scsi_Cmnd *cmd) ...@@ -919,7 +896,8 @@ int idescsi_reset (Scsi_Cmnd *cmd)
} }
/* FIXME - this will probably leak memory */ /* FIXME - this will probably leak memory */
HWGROUP(drive)->rq = NULL; HWGROUP(drive)->rq = NULL;
if (drive->driver_data) ((idescsi_scsi_t *)drive->driver_data)->pc = NULL; if (drive_to_idescsi(drive))
drive_to_idescsi(drive)->pc = NULL;
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
/* finally, reset the drive (and its partner on the bus...) */ /* finally, reset the drive (and its partner on the bus...) */
ide_do_reset (drive); ide_do_reset (drive);
...@@ -929,7 +907,8 @@ int idescsi_reset (Scsi_Cmnd *cmd) ...@@ -929,7 +907,8 @@ int idescsi_reset (Scsi_Cmnd *cmd)
static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev, static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int *parm) sector_t capacity, int *parm)
{ {
ide_drive_t *drive = idescsi_drives[sdev->id]; 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) { if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
parm[0] = drive->bios_head; parm[0] = drive->bios_head;
...@@ -956,10 +935,9 @@ static Scsi_Host_Template idescsi_template = { ...@@ -956,10 +935,9 @@ static Scsi_Host_Template idescsi_template = {
.max_sectors = 128, .max_sectors = 128,
.use_clustering = DISABLE_CLUSTERING, .use_clustering = DISABLE_CLUSTERING,
.emulated = 1, .emulated = 1,
.proc_name = "ide-scsi",
}; };
static struct Scsi_Host *idescsi_host;
static struct device idescsi_primary = { static struct device idescsi_primary = {
.name = "Ide-scsi Parent", .name = "Ide-scsi Parent",
.bus_id = "ide-scsi", .bus_id = "ide-scsi",
...@@ -968,39 +946,60 @@ static struct bus_type idescsi_emu_bus = { ...@@ -968,39 +946,60 @@ static struct bus_type idescsi_emu_bus = {
.name = "ide-scsi", .name = "ide-scsi",
}; };
static int __init init_idescsi_module(void) static int idescsi_attach(ide_drive_t *drive)
{ {
int id; idescsi_scsi_t *idescsi;
int last_lun = 0; struct Scsi_Host *host;
int err;
ide_register_driver(&idescsi_driver); if (!strstr("ide-scsi", drive->driver_req) ||
device_register(&idescsi_primary); !drive->present ||
bus_register (&idescsi_emu_bus); drive->media == ide_disk ||
idescsi_template.proc_name = "ide-scsi"; !(host = scsi_register(&idescsi_template,sizeof(idescsi_scsi_t))))
idescsi_host = scsi_register(&idescsi_template, 0);
if(idescsi_host == NULL)
return 1; return 1;
for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++) host->max_id = 1;
last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun); host->max_lun = 1;
idescsi_host->max_id = id; drive->driver_data = host;
idescsi_host->max_lun = last_lun + 1; idescsi = scsihost_to_idescsi(host);
scsi_add_host(idescsi_host, &idescsi_primary); idescsi->drive = drive;
return 0; err = ide_register_subdriver (drive, &idescsi_driver,
IDE_SUBDRIVER_VERSION);
if (!err) {
idescsi_setup (drive, idescsi);
drive->disk->fops = &idescsi_ops;
err = scsi_add_host(host, &idescsi_primary);
if (!err)
return 0;
/* fall through on error */
ide_unregister_subdriver(drive);
}
scsi_unregister(host);
return err;
} }
static void __exit exit_idescsi_module(void) static int __init init_idescsi_module(void)
{ {
ide_drive_t *drive; int err;
int id;
scsi_remove_host(idescsi_host); err = bus_register(&idescsi_emu_bus);
for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) { if (!err) {
drive = idescsi_drives[id]; err = device_register(&idescsi_primary);
if (drive) if (!err) {
DRIVER(drive)->busy = 0; err = ide_register_driver(&idescsi_driver);
if (!err)
return 0;
device_unregister(&idescsi_primary);
}
bus_unregister(&idescsi_emu_bus);
} }
scsi_unregister (idescsi_host); return err;
}
static void __exit exit_idescsi_module(void)
{
device_unregister(&idescsi_primary); device_unregister(&idescsi_primary);
bus_unregister (&idescsi_emu_bus); bus_unregister (&idescsi_emu_bus);
ide_unregister_driver(&idescsi_driver); ide_unregister_driver(&idescsi_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment