Commit 49ce412f authored by James Bottomley's avatar James Bottomley

Merge dougg/cloos changes in sbp2.h

parents 32e71bf0 f4e01df0
...@@ -3137,7 +3137,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) ...@@ -3137,7 +3137,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
/* /*
* Called by scsi stack to get bios parameters (used by fdisk, and at boot). * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
*/ */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,43)
static int sbp2scsi_biosparam (struct scsi_device *sdev, static int sbp2scsi_biosparam (struct scsi_device *sdev,
struct block_device *dev, sector_t capacity, int geom[]) struct block_device *dev, sector_t capacity, int geom[])
{ {
......
...@@ -552,7 +552,8 @@ void sbp2scsi_setup(char *str, int *ints); ...@@ -552,7 +552,8 @@ void sbp2scsi_setup(char *str, int *ints);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44)
static int sbp2scsi_biosparam (struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]); static int sbp2scsi_biosparam (struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]);
#else #else
static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); static int sbp2scsi_biosparam (struct scsi_device *sdev,
struct block_device *dev, sector_t capacy, int geom[]);
#endif #endif
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); static int sbp2scsi_abort (Scsi_Cmnd *SCpnt);
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); static int sbp2scsi_reset (Scsi_Cmnd *SCpnt);
......
...@@ -85,23 +85,6 @@ config BLK_DEV_SR_VENDOR ...@@ -85,23 +85,6 @@ config BLK_DEV_SR_VENDOR
drives (and HP Writers). If you have such a drive and get the first drives (and HP Writers). If you have such a drive and get the first
session only, try saying Y here; everybody else says N. session only, try saying Y here; everybody else says N.
config SR_EXTRA_DEVS
int "Maximum number of CDROM devices that can be loaded as modules"
depends on BLK_DEV_SR
default "2"
---help---
This controls the amount of additional space allocated in tables for
drivers that are loaded as modules after the kernel is booted. In
the event that the SCSI core itself was loaded as a module, this
value is the number of additional CD-ROMs that can be loaded after
the first host driver is loaded.
Admittedly this isn't pretty, but there are tons of race conditions
involved with resizing the internal arrays on the fly. Someday this
flag will go away, and everything will work automatically.
If you don't understand what's going on, go with the default.
config CHR_DEV_SG config CHR_DEV_SG
tristate "SCSI generic support" tristate "SCSI generic support"
depends on SCSI depends on SCSI
......
...@@ -45,13 +45,9 @@ ...@@ -45,13 +45,9 @@
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
LIST_HEAD(scsi_host_tmpl_list); static LIST_HEAD(scsi_host_hn_list);
LIST_HEAD(scsi_host_hn_list); static LIST_HEAD(scsi_host_list);
static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(scsi_host_list);
spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
struct Scsi_Device_Template * scsi_devicelist;
static int scsi_host_next_hn; /* host_no for next new host */ static int scsi_host_next_hn; /* host_no for next new host */
static int scsi_hosts_registered; /* cnt of registered scsi hosts */ static int scsi_hosts_registered; /* cnt of registered scsi hosts */
...@@ -94,7 +90,7 @@ int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int ...@@ -94,7 +90,7 @@ int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int
* This is the default case for the release function. Its completely * This is the default case for the release function. Its completely
* useless for anything but old ISA adapters * useless for anything but old ISA adapters
**/ **/
static void scsi_host_generic_release(struct Scsi_Host *shost) static void scsi_host_legacy_release(struct Scsi_Host *shost)
{ {
if (shost->irq) if (shost->irq)
free_irq(shost->irq, NULL); free_irq(shost->irq, NULL);
...@@ -104,19 +100,35 @@ static void scsi_host_generic_release(struct Scsi_Host *shost) ...@@ -104,19 +100,35 @@ static void scsi_host_generic_release(struct Scsi_Host *shost)
release_region(shost->io_port, shost->n_io_port); release_region(shost->io_port, shost->n_io_port);
} }
static int scsi_remove_legacy_host(struct Scsi_Host *shost)
{
int error, pcount = scsi_hosts_registered;
error = scsi_remove_host(shost);
if (error)
return error;
if (shost->hostt->release)
(*shost->hostt->release)(shost);
else
scsi_host_legacy_release(shost);
if (pcount == scsi_hosts_registered)
scsi_unregister(shost);
return 0;
}
/** /**
* scsi_host_chk_and_release - check a scsi host for release and release * scsi_remove_host - check a scsi host for release and release
* @shost: a pointer to a scsi host to release * @shost: a pointer to a scsi host to release
* *
* Return value: * Return value:
* 0 on Success / 1 on Failure * 0 on Success / 1 on Failure
**/ **/
int scsi_host_chk_and_release(struct Scsi_Host *shost) int scsi_remove_host(struct Scsi_Host *shost)
{ {
int pcount; struct scsi_device *sdev;
Scsi_Device *sdev; struct scsi_cmnd *scmd;
struct Scsi_Device_Template *sdev_tp;
Scsi_Cmnd *scmd;
/* /*
* Current policy is all shosts go away on unregister. * Current policy is all shosts go away on unregister.
...@@ -175,10 +187,7 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost) ...@@ -175,10 +187,7 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost)
* structures * structures
*/ */
for (sdev = shost->host_queue; sdev; sdev = sdev->next) { for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
for (sdev_tp = scsi_devicelist; sdev_tp; scsi_detach_device(sdev);
sdev_tp = sdev_tp->next)
if (sdev_tp->detach)
(*sdev_tp->detach) (sdev);
/* If something still attached, punt */ /* If something still attached, punt */
if (sdev->attached) { if (sdev->attached) {
...@@ -186,10 +195,6 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost) ...@@ -186,10 +195,6 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost)
sdev->attached); sdev->attached);
return 1; return 1;
} }
if (shost->hostt->slave_detach)
(*shost->hostt->slave_detach) (sdev);
devfs_unregister(sdev->de); devfs_unregister(sdev->de);
device_unregister(&sdev->sdev_driverfs_dev); device_unregister(&sdev->sdev_driverfs_dev);
} }
...@@ -198,7 +203,6 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost) ...@@ -198,7 +203,6 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost)
for (sdev = shost->host_queue; sdev; for (sdev = shost->host_queue; sdev;
sdev = shost->host_queue) { sdev = shost->host_queue) {
scsi_release_commandblocks(sdev);
blk_cleanup_queue(&sdev->request_queue); blk_cleanup_queue(&sdev->request_queue);
/* Next free up the Scsi_Device structures for this host */ /* Next free up the Scsi_Device structures for this host */
shost->host_queue = sdev->next; shost->host_queue = sdev->next;
...@@ -207,18 +211,30 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost) ...@@ -207,18 +211,30 @@ int scsi_host_chk_and_release(struct Scsi_Host *shost)
kfree(sdev); kfree(sdev);
} }
/* Remove the instance of the individual hosts */ return 0;
pcount = scsi_hosts_registered; }
if (shost->hostt->release)
(*shost->hostt->release) (shost);
else {
scsi_host_generic_release(shost);
}
if (pcount == scsi_hosts_registered) int scsi_add_host(struct Scsi_Host *shost)
scsi_unregister(shost); {
Scsi_Host_Template *sht = shost->hostt;
struct scsi_device *sdev;
int error = 0;
return 0; printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
sht->info ? sht->info(shost) : sht->name);
device_register(&shost->host_driverfs_dev);
scan_scsis(shost, 0, 0, 0, 0);
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
if (sdev->host->hostt != sht)
continue; /* XXX(hch): can this really happen? */
error = scsi_attach_device(sdev);
if (error)
break;
}
return error;
} }
/** /**
...@@ -459,7 +475,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) ...@@ -459,7 +475,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
return shost; return shost;
} }
/** /**
* scsi_register_host - register a low level host driver * scsi_register_host - register a low level host driver
* @shost_tp: pointer to a scsi host driver template * @shost_tp: pointer to a scsi host driver template
...@@ -469,13 +484,8 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) ...@@ -469,13 +484,8 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
**/ **/
int scsi_register_host(Scsi_Host_Template *shost_tp) int scsi_register_host(Scsi_Host_Template *shost_tp)
{ {
int cur_cnt;
Scsi_Device *sdev;
struct Scsi_Device_Template *sdev_tp;
struct list_head *lh;
struct Scsi_Host *shost; struct Scsi_Host *shost;
int cur_cnt;
INIT_LIST_HEAD(&shost_tp->shtp_list);
/* /*
* Check no detect routine. * Check no detect routine.
...@@ -503,80 +513,40 @@ int scsi_register_host(Scsi_Host_Template *shost_tp) ...@@ -503,80 +513,40 @@ int scsi_register_host(Scsi_Host_Template *shost_tp)
* registration code below. * registration code below.
*/ */
shost_tp->detect(shost_tp); shost_tp->detect(shost_tp);
if (!shost_tp->present)
if (shost_tp->present) { return 0;
/*
* FIXME Who needs manual registration and why??? if (cur_cnt == scsi_hosts_registered) {
*/ if (shost_tp->present > 1) {
if (cur_cnt == scsi_hosts_registered) { printk(KERN_ERR "scsi: Failure to register"
if (shost_tp->present > 1) { "low-level scsi driver");
printk(KERN_ERR "scsi: Failure to register" scsi_unregister_host(shost_tp);
"low-level scsi driver"); return 1;
scsi_unregister_host(shost_tp);
return 1;
}
/*
* The low-level driver failed to register a driver.
* We can do this now.
*/
if(scsi_register(shost_tp, 0)==NULL) {
printk(KERN_ERR "scsi: register failed.\n");
scsi_unregister_host(shost_tp);
return 1;
}
}
list_add_tail(&shost_tp->shtp_list, &scsi_host_tmpl_list);
/* The next step is to call scan_scsis here. This generates the
* Scsi_Devices entries
*/
list_for_each(lh, &scsi_host_list) {
shost = list_entry(lh, struct Scsi_Host, sh_list);
if (shost->hostt == shost_tp) {
const char *dm_name;
if (shost_tp->info) {
dm_name = shost_tp->info(shost);
} else {
dm_name = shost_tp->name;
}
printk(KERN_INFO "scsi%d : %s\n",
shost->host_no, dm_name);
/* first register parent with driverfs */
device_register(&shost->host_driverfs_dev);
scan_scsis(shost, 0, 0, 0, 0);
}
}
for (sdev_tp = scsi_devicelist; sdev_tp;
sdev_tp = sdev_tp->next) {
if (sdev_tp->init && sdev_tp->dev_noticed)
(*sdev_tp->init) ();
} }
/* /*
* Next we create the Scsi_Cmnd structures for this host * The low-level driver failed to register a driver.
* We can do this now.
*
* XXX Who needs manual registration and why???
*/ */
list_for_each(lh, &scsi_host_list) { if (!scsi_register(shost_tp, 0)) {
shost = list_entry(lh, struct Scsi_Host, sh_list); printk(KERN_ERR "scsi: register failed.\n");
for (sdev = shost->host_queue; sdev; sdev = sdev->next) scsi_unregister_host(shost_tp);
if (sdev->host->hostt == shost_tp) { return 1;
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0)
goto out_of_space;
for (sdev_tp = scsi_devicelist;
sdev_tp;
sdev_tp = sdev_tp->next)
if (sdev_tp->attach)
(*sdev_tp->attach) (sdev);
if (!sdev->attached) {
scsi_release_commandblocks(sdev);
}
}
} }
} }
/*
* XXX(hch) use scsi_tp_for_each_host() once it propagates
* error returns properly.
*/
list_for_each_entry(shost, &scsi_host_list, sh_list)
if (shost->hostt == shost_tp)
if (scsi_add_host(shost))
goto out_of_space;
return 0; return 0;
out_of_space: out_of_space:
...@@ -608,20 +578,12 @@ int scsi_unregister_host(Scsi_Host_Template *shost_tp) ...@@ -608,20 +578,12 @@ int scsi_unregister_host(Scsi_Host_Template *shost_tp)
pcount = scsi_hosts_registered; pcount = scsi_hosts_registered;
scsi_tp_for_each_host(shost_tp, scsi_host_chk_and_release); scsi_tp_for_each_host(shost_tp, scsi_remove_legacy_host);
if (pcount != scsi_hosts_registered) if (pcount != scsi_hosts_registered)
printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered, printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered,
(scsi_hosts_registered == 1) ? "" : "s"); (scsi_hosts_registered == 1) ? "" : "s");
/*
* Remove it from the list if all
* hosts were successfully removed (ie preset == 0)
*/
if (!shost_tp->present) {
list_del(&shost_tp->shtp_list);
}
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
unlock_kernel(); unlock_kernel();
......
...@@ -57,9 +57,6 @@ typedef struct scsi_disk Disk; ...@@ -57,9 +57,6 @@ typedef struct scsi_disk Disk;
typedef struct SHT typedef struct SHT
{ {
struct list_head shtp_list;
/* Used with loadable modules so that we know when it is safe to unload */ /* Used with loadable modules so that we know when it is safe to unload */
struct module * module; struct module * module;
...@@ -96,12 +93,6 @@ typedef struct SHT ...@@ -96,12 +93,6 @@ typedef struct SHT
*/ */
int (* detect)(struct SHT *); int (* detect)(struct SHT *);
/*
* This function is only used by one driver and will be going away
* once it switches over to using the slave_detach() function instead.
*/
int (*revoke)(Scsi_Device *);
/* Used with loadable modules to unload the host structures. Note: /* Used with loadable modules to unload the host structures. Note:
* there is a default action built into the modules code which may * there is a default action built into the modules code which may
* be sufficient for most host adapters. Thus you may not have to supply * be sufficient for most host adapters. Thus you may not have to supply
...@@ -520,8 +511,6 @@ typedef struct SHN ...@@ -520,8 +511,6 @@ typedef struct SHN
unsigned short host_registered; unsigned short host_registered;
} Scsi_Host_Name; } Scsi_Host_Name;
extern struct Scsi_Device_Template * scsi_devicelist;
extern void scsi_proc_host_mkdir(Scsi_Host_Template *); extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
extern void scsi_proc_host_add(struct Scsi_Host *); extern void scsi_proc_host_add(struct Scsi_Host *);
extern void scsi_proc_host_rm(struct Scsi_Host *); extern void scsi_proc_host_rm(struct Scsi_Host *);
...@@ -533,8 +522,6 @@ extern void scsi_proc_host_rm(struct Scsi_Host *); ...@@ -533,8 +522,6 @@ extern void scsi_proc_host_rm(struct Scsi_Host *);
extern int next_scsi_host; extern int next_scsi_host;
unsigned int scsi_init(void); unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int);
extern void scsi_unregister(struct Scsi_Host *);
extern void scsi_register_blocked_host(struct Scsi_Host *); extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *); extern void scsi_deregister_blocked_host(struct Scsi_Host *);
...@@ -567,13 +554,7 @@ struct Scsi_Device_Template ...@@ -567,13 +554,7 @@ struct Scsi_Device_Template
const char * tag; const char * tag;
struct module * module; /* Used for loadable modules */ struct module * module; /* Used for loadable modules */
unsigned char scsi_type; unsigned char scsi_type;
unsigned int nr_dev; /* Number currently attached */
unsigned int dev_noticed; /* Number of devices detected. */
unsigned int dev_max; /* Current size of arrays */
unsigned blk:1; /* 0 if character device */
int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */ int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
int (*init)(void); /* Sizes arrays based upon number of devices
* detected */
int (*attach)(Scsi_Device *); /* Attach devices to arrays */ int (*attach)(Scsi_Device *); /* Attach devices to arrays */
void (*detach)(Scsi_Device *); void (*detach)(Scsi_Device *);
int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code.
...@@ -585,10 +566,26 @@ void scsi_initialize_queue(Scsi_Device *, struct Scsi_Host *); ...@@ -585,10 +566,26 @@ void scsi_initialize_queue(Scsi_Device *, struct Scsi_Host *);
/* /*
* Driver registration/unregistration. * Highlevel driver registration/unregistration.
*/ */
extern int scsi_register_device(struct Scsi_Device_Template *); extern int scsi_register_device(struct Scsi_Device_Template *);
extern int scsi_unregister_device(struct Scsi_Device_Template *); extern int scsi_unregister_device(struct Scsi_Device_Template *);
/*
* HBA allocation/freeing.
*/
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int);
extern void scsi_unregister(struct Scsi_Host *);
/*
* HBA registration/unregistration.
*/
extern int scsi_add_host(struct Scsi_Host *);
extern int scsi_remove_host(struct Scsi_Host *);
/*
* Legacy HBA template registration/unregistration.
*/
extern int scsi_register_host(Scsi_Host_Template *); extern int scsi_register_host(Scsi_Host_Template *);
extern int scsi_unregister_host(Scsi_Host_Template *); extern int scsi_unregister_host(Scsi_Host_Template *);
...@@ -605,28 +602,6 @@ extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); ...@@ -605,28 +602,6 @@ extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_failed_inc_and_test(struct Scsi_Host *); extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
/*
* This is an ugly hack. If we expect to be able to load devices at run time,
* we need to leave extra room in some of the data structures. Doing a
* realloc to enlarge the structures would be riddled with race conditions,
* so until a better solution is discovered, we use this crude approach
*
* Even bigger hack for SparcSTORAGE arrays. Those are at least 6 disks, but
* usually up to 30 disks, so everyone would need to change this. -jj
*
* Note: These things are all evil and all need to go away. My plan is to
* tackle the character devices first, as there aren't any locking implications
* in the block device layer. The block devices will require more work.
*
* The generics driver has been updated to resize as required. So as the tape
* driver. Two down, two more to go.
*/
#ifndef CONFIG_SR_EXTRA_DEVS
#define CONFIG_SR_EXTRA_DEVS 2
#endif
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
/** /**
* scsi_find_device - find a device given the host * scsi_find_device - find a device given the host
* @shost: SCSI host pointer * @shost: SCSI host pointer
......
...@@ -2865,16 +2865,14 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl, ...@@ -2865,16 +2865,14 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
pciDevFun = pdev->devfn; pciDevFun = pdev->devfn;
#endif #endif
if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
pcibios_read_config_word (pciBus, pciDevFun, pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
PCI_CONF_AMISIG, &magic);
if ((magic != AMI_SIGNATURE) if ((magic != AMI_SIGNATURE)
&& (magic != AMI_SIGNATURE_471)) { && (magic != AMI_SIGNATURE_471)) {
pciIdx++; pciIdx++;
continue; /* not an AMI board */ continue; /* not an AMI board */
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pcibios_read_config_dword (pciBus, pciDevFun, pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64);
PCI_CONF_AMISIG64, &magic64);
if (magic64 == AMI_64BIT_SIGNATURE) if (magic64 == AMI_64BIT_SIGNATURE)
flag |= BOARD_64BIT; flag |= BOARD_64BIT;
...@@ -3215,7 +3213,6 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl) ...@@ -3215,7 +3213,6 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI, count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ); PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
mega_reorder_hosts ();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (count) { if (count) {
...@@ -3481,173 +3478,6 @@ mega_get_boot_ldrv(mega_host_config *megacfg) ...@@ -3481,173 +3478,6 @@ mega_get_boot_ldrv(mega_host_config *megacfg)
} }
static void mega_reorder_hosts (void)
{
struct Scsi_Host *shpnt;
struct Scsi_Host *shone;
struct Scsi_Host *shtwo;
mega_host_config *boot_host;
int i;
/*
* Find the (first) host which has it's BIOS enabled
*/
boot_host = NULL;
for (i = 0; i < MAX_CONTROLLERS; i++) {
if (mega_hbas[i].is_bios_enabled) {
boot_host = mega_hbas[i].hostdata_addr;
break;
}
}
if (boot_host == NULL) {
printk (KERN_WARNING "megaraid: no BIOS enabled.\n");
return;
}
/*
* Traverse through the list of SCSI hosts for our HBA locations
*/
shone = shtwo = NULL;
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
/* Is it one of ours? */
for (i = 0; i < MAX_CONTROLLERS; i++) {
if ((mega_host_config *) shpnt->hostdata ==
mega_hbas[i].hostdata_addr) {
/* Does this one has BIOS enabled */
if (mega_hbas[i].hostdata_addr == boot_host) {
/* Are we first */
if (shtwo == NULL) /* Yes! */
return;
else { /* :-( */
shone = shpnt;
}
} else {
if (!shtwo) {
/* were we here before? xchng first */
shtwo = shpnt;
}
}
break;
}
}
/*
* Have we got the boot host and one which does not have the bios
* enabled.
*/
if (shone && shtwo)
break;
}
if (shone && shtwo) {
mega_swap_hosts (shone, shtwo);
}
return;
}
static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
{
struct Scsi_Host *prevtoshtwo;
struct Scsi_Host *prevtoshone;
struct Scsi_Host *save = NULL;;
/* Are these two nodes adjacent */
if (shtwo->next == shone) {
if (shtwo == scsi_hostlist && shone->next == NULL) {
/* just two nodes */
scsi_hostlist = shone;
shone->next = shtwo;
shtwo->next = NULL;
} else if (shtwo == scsi_hostlist) {
/* first two nodes of the list */
scsi_hostlist = shone;
shtwo->next = shone->next;
scsi_hostlist->next = shtwo;
} else if (shone->next == NULL) {
/* last two nodes of the list */
prevtoshtwo = scsi_hostlist;
while (prevtoshtwo->next != shtwo)
prevtoshtwo = prevtoshtwo->next;
prevtoshtwo->next = shone;
shone->next = shtwo;
shtwo->next = NULL;
} else {
prevtoshtwo = scsi_hostlist;
while (prevtoshtwo->next != shtwo)
prevtoshtwo = prevtoshtwo->next;
prevtoshtwo->next = shone;
shtwo->next = shone->next;
shone->next = shtwo;
}
} else if (shtwo == scsi_hostlist && shone->next == NULL) {
/* shtwo at head, shone at tail, not adjacent */
prevtoshone = scsi_hostlist;
while (prevtoshone->next != shone)
prevtoshone = prevtoshone->next;
scsi_hostlist = shone;
shone->next = shtwo->next;
prevtoshone->next = shtwo;
shtwo->next = NULL;
} else if (shtwo == scsi_hostlist && shone->next != NULL) {
/* shtwo at head, shone is not at tail */
prevtoshone = scsi_hostlist;
while (prevtoshone->next != shone)
prevtoshone = prevtoshone->next;
scsi_hostlist = shone;
prevtoshone->next = shtwo;
save = shtwo->next;
shtwo->next = shone->next;
shone->next = save;
} else if (shone->next == NULL) {
/* shtwo not at head, shone at tail */
prevtoshtwo = scsi_hostlist;
prevtoshone = scsi_hostlist;
while (prevtoshtwo->next != shtwo)
prevtoshtwo = prevtoshtwo->next;
while (prevtoshone->next != shone)
prevtoshone = prevtoshone->next;
prevtoshtwo->next = shone;
shone->next = shtwo->next;
prevtoshone->next = shtwo;
shtwo->next = NULL;
} else {
prevtoshtwo = scsi_hostlist;
prevtoshone = scsi_hostlist;
save = NULL;;
while (prevtoshtwo->next != shtwo)
prevtoshtwo = prevtoshtwo->next;
while (prevtoshone->next != shone)
prevtoshone = prevtoshone->next;
prevtoshtwo->next = shone;
save = shone->next;
shone->next = shtwo->next;
prevtoshone->next = shtwo;
shtwo->next = save;
}
return;
}
static inline void mega_freeSgList (mega_host_config * megaCfg) static inline void mega_freeSgList (mega_host_config * megaCfg)
{ {
int i; int i;
...@@ -4235,7 +4065,7 @@ int megaraid_biosparam (struct scsi_device *sdev, struct block_device *bdev, ...@@ -4235,7 +4065,7 @@ int megaraid_biosparam (struct scsi_device *sdev, struct block_device *bdev,
/* Default heads (64) & sectors (32) */ /* Default heads (64) & sectors (32) */
heads = 64; heads = 64;
sectors = 32; sectors = 32;
cylinders = (unsigned long)capacity / (heads * sectors); cylinders = (unsigned long)capacity >> 11;
/* Handle extended translation size for logical drives > 1Gb */ /* Handle extended translation size for logical drives > 1Gb */
if (capacity >= 0x200000) { if (capacity >= 0x200000) {
...@@ -4293,7 +4123,6 @@ mega_partsize(struct block_device *bdev, sector_t capacity, int *geom) ...@@ -4293,7 +4123,6 @@ mega_partsize(struct block_device *bdev, sector_t capacity, int *geom)
struct partition *p, *largest = NULL; struct partition *p, *largest = NULL;
int i, largest_cyl; int i, largest_cyl;
int heads, cyls, sectors; int heads, cyls, sectors;
int capacity = capacity;
unsigned char *buf; unsigned char *buf;
if (!(buf = scsi_bios_ptable(bdev))) if (!(buf = scsi_bios_ptable(bdev)))
...@@ -4324,7 +4153,7 @@ mega_partsize(struct block_device *bdev, sector_t capacity, int *geom) ...@@ -4324,7 +4153,7 @@ mega_partsize(struct block_device *bdev, sector_t capacity, int *geom)
return -1; return -1;
} }
cyls = capacity/(heads * sectors); cyls = (unsigned long)capacity/(heads * sectors);
geom[0] = heads; geom[0] = heads;
geom[1] = sectors; geom[1] = sectors;
...@@ -4683,12 +4512,7 @@ static int megadev_ioctl (struct inode *inode, struct file *filep, ...@@ -4683,12 +4512,7 @@ static int megadev_ioctl (struct inode *inode, struct file *filep,
/* /*
* Find this host * Find this host
*/ */
for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) { shpnt = megaCtlrs[adapno]->host;
if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
megacfg = (mega_host_config *)shpnt->hostdata;
break;
}
}
if(shpnt == NULL) return -ENODEV; if(shpnt == NULL) return -ENODEV;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
...@@ -4803,12 +4627,7 @@ static int megadev_ioctl (struct inode *inode, struct file *filep, ...@@ -4803,12 +4627,7 @@ static int megadev_ioctl (struct inode *inode, struct file *filep,
/* /*
* Find this host * Find this host
*/ */
for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) { shpnt = megaCtlrs[adapno]->host;
if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
megacfg = (mega_host_config *)shpnt->hostdata;
break;
}
}
if(shpnt == NULL) return -ENODEV; if(shpnt == NULL) return -ENODEV;
/* /*
......
...@@ -214,8 +214,6 @@ ...@@ -214,8 +214,6 @@
info: megaraid_info, /* Driver Info Function */\ info: megaraid_info, /* Driver Info Function */\
command: megaraid_command, /* Command Function */\ command: megaraid_command, /* Command Function */\
queuecommand: megaraid_queue, /* Queue Command Function */\ queuecommand: megaraid_queue, /* Queue Command Function */\
abort: megaraid_abort, /* Abort Command Function */\
reset: megaraid_reset, /* Reset Command Function */\
bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\
can_queue: MAX_COMMANDS, /* Can Queue */\ can_queue: MAX_COMMANDS, /* Can Queue */\
this_id: 7, /* HBA Target ID */\ this_id: 7, /* HBA Target ID */\
...@@ -989,8 +987,6 @@ static void enq_scb_freelist (mega_host_config *, mega_scb *, ...@@ -989,8 +987,6 @@ static void enq_scb_freelist (mega_host_config *, mega_scb *,
int lock, int intr); int lock, int intr);
static int mega_is_bios_enabled (mega_host_config *); static int mega_is_bios_enabled (mega_host_config *);
static void mega_reorder_hosts (void);
static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
static void mega_create_proc_entry (int index, struct proc_dir_entry *); static void mega_create_proc_entry (int index, struct proc_dir_entry *);
static int mega_support_ext_cdb(mega_host_config *); static int mega_support_ext_cdb(mega_host_config *);
......
...@@ -156,6 +156,10 @@ static int osst_attach(Scsi_Device *); ...@@ -156,6 +156,10 @@ static int osst_attach(Scsi_Device *);
static int osst_detect(Scsi_Device *); static int osst_detect(Scsi_Device *);
static void osst_detach(Scsi_Device *); static void osst_detach(Scsi_Device *);
static int osst_dev_noticed;
static int osst_nr_dev;
static int osst_dev_max;
struct Scsi_Device_Template osst_template = struct Scsi_Device_Template osst_template =
{ {
module: THIS_MODULE, module: THIS_MODULE,
...@@ -163,7 +167,6 @@ struct Scsi_Device_Template osst_template = ...@@ -163,7 +167,6 @@ struct Scsi_Device_Template osst_template =
tag: "osst", tag: "osst",
scsi_type: TYPE_TAPE, scsi_type: TYPE_TAPE,
detect: osst_detect, detect: osst_detect,
init: osst_init,
attach: osst_attach, attach: osst_attach,
detach: osst_detach detach: osst_detach
}; };
...@@ -4155,7 +4158,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4155,7 +4158,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
char *name; char *name;
int mode = TAPE_MODE(inode->i_rdev); int mode = TAPE_MODE(inode->i_rdev);
if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device) if (dev >= osst_dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
return (-ENXIO); return (-ENXIO);
filp->private_data = STp; filp->private_data = STp;
...@@ -4980,7 +4983,7 @@ static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma ) ...@@ -4980,7 +4983,7 @@ static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
int i, priority, b_size, order, got = 0, segs = 0; int i, priority, b_size, order, got = 0, segs = 0;
OSST_buffer *tb; OSST_buffer *tb;
if (osst_nbr_buffers >= osst_template.dev_max) if (osst_nbr_buffers >= osst_dev_max)
return NULL; /* Should never happen */ return NULL; /* Should never happen */
if (from_initialization) if (from_initialization)
...@@ -5411,26 +5414,31 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5411,26 +5414,31 @@ static int osst_attach(Scsi_Device * SDp)
if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return 1; return 1;
osst_init();
disk = alloc_disk(1); disk = alloc_disk(1);
if (!disk) if (!disk)
return 1; return 1;
if (osst_template.nr_dev >= osst_template.dev_max) { if (osst_nr_dev >= osst_dev_max) {
SDp->attached--;
put_disk(disk); put_disk(disk);
return 1; return 1;
} }
if (scsi_slave_attach(SDp))
return 1;
/* find a free minor number */ /* find a free minor number */
for (i=0; os_scsi_tapes[i] && i<osst_template.dev_max; i++); for (i=0; os_scsi_tapes[i] && i<osst_dev_max; i++);
if(i >= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)"); if(i >= osst_dev_max) panic ("Scsi_devices corrupt (osst)");
/* allocate a OS_Scsi_Tape for this device */ /* allocate a OS_Scsi_Tape for this device */
tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC); tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
if (tpnt == NULL) { if (tpnt == NULL) {
SDp->attached--;
printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n"); printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n");
put_disk(disk); put_disk(disk);
scsi_slave_detach(SDp);
return 1; return 1;
} }
memset(tpnt, 0, sizeof(OS_Scsi_Tape)); memset(tpnt, 0, sizeof(OS_Scsi_Tape));
...@@ -5547,7 +5555,7 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5547,7 +5555,7 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock); init_MUTEX(&tpnt->lock);
osst_template.nr_dev++; osst_nr_dev++;
printk(KERN_INFO printk(KERN_INFO
"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n", "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
...@@ -5561,7 +5569,7 @@ static int osst_detect(Scsi_Device * SDp) ...@@ -5561,7 +5569,7 @@ static int osst_detect(Scsi_Device * SDp)
if (SDp->type != TYPE_TAPE) return 0; if (SDp->type != TYPE_TAPE) return 0;
if ( ! osst_supports(SDp) ) return 0; if ( ! osst_supports(SDp) ) return 0;
osst_template.dev_noticed++; osst_dev_noticed++;
return 1; return 1;
} }
...@@ -5572,7 +5580,7 @@ static int osst_init() ...@@ -5572,7 +5580,7 @@ static int osst_init()
{ {
int i; int i;
if (osst_template.dev_noticed == 0) if (osst_dev_noticed == 0)
return 0; return 0;
if (!osst_registered) { if (!osst_registered) {
...@@ -5585,10 +5593,10 @@ static int osst_init() ...@@ -5585,10 +5593,10 @@ static int osst_init()
if (os_scsi_tapes) if (os_scsi_tapes)
return 0; return 0;
osst_template.dev_max = OSST_MAX_TAPES; osst_dev_max = OSST_MAX_TAPES;
if (osst_template.dev_max > 128 / ST_NBR_MODES) if (osst_dev_max > 128 / ST_NBR_MODES)
printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
os_scsi_tapes = kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *), os_scsi_tapes = kmalloc(osst_dev_max * sizeof(OS_Scsi_Tape *),
GFP_ATOMIC); GFP_ATOMIC);
if (!os_scsi_tapes) { if (!os_scsi_tapes) {
printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n"); printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n");
...@@ -5596,11 +5604,11 @@ static int osst_init() ...@@ -5596,11 +5604,11 @@ static int osst_init()
return 1; return 1;
} }
for (i=0; i < osst_template.dev_max; ++i) for (i=0; i < osst_dev_max; ++i)
os_scsi_tapes[i] = NULL; os_scsi_tapes[i] = NULL;
/* Allocate the buffer pointers */ /* Allocate the buffer pointers */
osst_buffers = kmalloc(osst_template.dev_max * sizeof(OSST_buffer *), osst_buffers = kmalloc(osst_dev_max * sizeof(OSST_buffer *),
GFP_ATOMIC); GFP_ATOMIC);
if (!osst_buffers) { if (!osst_buffers) {
printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n"); printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n");
...@@ -5628,7 +5636,7 @@ static void osst_detach(Scsi_Device * SDp) ...@@ -5628,7 +5636,7 @@ static void osst_detach(Scsi_Device * SDp)
int mode; int mode;
#endif #endif
for(i=0; i<osst_template.dev_max; i++) { for(i=0; i<osst_dev_max; i++) {
tpnt = os_scsi_tapes[i]; tpnt = os_scsi_tapes[i];
if(tpnt != NULL && tpnt->device == SDp) { if(tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL; tpnt->device = NULL;
...@@ -5643,9 +5651,9 @@ static void osst_detach(Scsi_Device * SDp) ...@@ -5643,9 +5651,9 @@ static void osst_detach(Scsi_Device * SDp)
put_disk(tpnt->disk); put_disk(tpnt->disk);
kfree(tpnt); kfree(tpnt);
os_scsi_tapes[i] = NULL; os_scsi_tapes[i] = NULL;
SDp->attached--; scsi_slave_detach(SDp);
osst_template.nr_dev--; osst_nr_dev--;
osst_template.dev_noticed--; osst_dev_noticed--;
return; return;
} }
} }
...@@ -5667,7 +5675,7 @@ static void __exit exit_osst (void) ...@@ -5667,7 +5675,7 @@ static void __exit exit_osst (void)
unregister_chrdev(MAJOR_NR, "osst"); unregister_chrdev(MAJOR_NR, "osst");
osst_registered--; osst_registered--;
if (os_scsi_tapes) { if (os_scsi_tapes) {
for (i=0; i < osst_template.dev_max; ++i) { for (i=0; i < osst_dev_max; ++i) {
STp = os_scsi_tapes[i]; STp = os_scsi_tapes[i];
if (!STp) if (!STp)
continue; continue;
...@@ -5689,7 +5697,7 @@ static void __exit exit_osst (void) ...@@ -5689,7 +5697,7 @@ static void __exit exit_osst (void)
kfree(osst_buffers); kfree(osst_buffers);
} }
} }
osst_template.dev_max = 0; osst_dev_max = 0;
printk(KERN_INFO "osst :I: Unloaded.\n"); printk(KERN_INFO "osst :I: Unloaded.\n");
} }
......
...@@ -132,6 +132,12 @@ struct softscsi_data { ...@@ -132,6 +132,12 @@ struct softscsi_data {
static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned; static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned;
/*
* List of all highlevel drivers.
*/
static struct Scsi_Device_Template *scsi_devicelist;
static DECLARE_RWSEM(scsi_devicelist_mutex);
/* /*
* Note - the initial logging level can be set here to log events at boot time. * Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface. * After the system is up, you may enable logging via the /proc interface.
...@@ -1660,10 +1666,6 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags) ...@@ -1660,10 +1666,6 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags)
break; break;
} }
spin_unlock_irqrestore(&device_request_lock, flags); spin_unlock_irqrestore(&device_request_lock, flags);
if(SDpnt->current_queue_depth == 0)
{
scsi_build_commandblocks(SDpnt);
}
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -1720,7 +1722,6 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) ...@@ -1720,7 +1722,6 @@ static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
static int proc_scsi_gen_write(struct file * file, const char * buf, static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data) unsigned long length, void *data)
{ {
struct Scsi_Device_Template *SDTpnt;
Scsi_Device *scd; Scsi_Device *scd;
struct Scsi_Host *HBA_ptr; struct Scsi_Host *HBA_ptr;
char *p; char *p;
...@@ -1926,24 +1927,10 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -1926,24 +1927,10 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
if (scd->access_count) if (scd->access_count)
goto out; goto out;
SDTpnt = scsi_devicelist; scsi_detach_device(scd);
while (SDTpnt != NULL) {
if (SDTpnt->detach)
(*SDTpnt->detach) (scd);
SDTpnt = SDTpnt->next;
}
if (scd->attached == 0) { if (scd->attached == 0) {
/*
* Nobody is using this device any more.
* Free all of the command structures.
*/
if (HBA_ptr->hostt->revoke)
HBA_ptr->hostt->revoke(scd);
if (HBA_ptr->hostt->slave_detach)
(*HBA_ptr->hostt->slave_detach) (scd);
devfs_unregister (scd->de); devfs_unregister (scd->de);
scsi_release_commandblocks(scd);
/* Now we can remove the device structure */ /* Now we can remove the device structure */
if (scd->next != NULL) if (scd->next != NULL)
...@@ -1971,6 +1958,109 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -1971,6 +1958,109 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
} }
#endif #endif
void scsi_detect_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->detect)
(*sdt->detect)(sdev);
up_read(&scsi_devicelist_mutex);
}
int scsi_attach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->attach)
/*
* XXX check result when the upper level attach
* return values are fixed, and on failure goto
* fail.
*/
(*sdt->attach) (sdev);
up_read(&scsi_devicelist_mutex);
return 0;
fail:
printk(KERN_ERR "%s: Allocation failure during SCSI scanning, "
"some SCSI devices might not be configured\n",
__FUNCTION__);
return -ENOMEM;
}
void scsi_detach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->detach)
(*sdt->detach)(sdev);
up_read(&scsi_devicelist_mutex);
}
/*
* Function: scsi_slave_attach()
*
* Purpose: Called from the upper level driver attach to handle common
* attach code.
*
* Arguments: sdev - scsi_device to attach
*
* Returns: 1 on error, 0 on succes
*
* Lock Status: Protected via scsi_devicelist_mutex.
*/
int scsi_slave_attach(struct scsi_device *sdev)
{
if (sdev->attached++ == 0) {
/*
* No one was attached.
*/
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0) {
printk(KERN_ERR "scsi: Allocation failure during"
" attach, some SCSI devices might not be"
" configured\n");
return 1;
}
if (sdev->host->hostt->slave_attach != NULL) {
if (sdev->host->hostt->slave_attach(sdev) != 0) {
printk(KERN_INFO "scsi: failed low level driver"
" attach, some SCSI device might not be"
" configured\n");
scsi_release_commandblocks(sdev);
return 1;
}
} else if (sdev->host->cmd_per_lun != 0)
scsi_adjust_queue_depth(sdev, 0,
sdev->host->cmd_per_lun);
}
return 0;
}
/*
* Function: scsi_slave_detach()
*
* Purpose: Called from the upper level driver attach to handle common
* detach code.
*
* Arguments: sdev - struct scsi_device to detach
*
* Lock Status: Protected via scsi_devicelist_mutex.
*/
void scsi_slave_detach(struct scsi_device *sdev)
{
if (--sdev->attached == 0) {
if (sdev->host->hostt->slave_detach != NULL)
sdev->host->hostt->slave_detach(sdev);
scsi_release_commandblocks(sdev);
}
}
/* /*
* This entry point should be called by a loadable module if it is trying * This entry point should be called by a loadable module if it is trying
* add a high level scsi driver to the system. * add a high level scsi driver to the system.
...@@ -1989,8 +2079,10 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) ...@@ -1989,8 +2079,10 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
if (tpnt->next) if (tpnt->next)
return 1; return 1;
down_write(&scsi_devicelist_mutex);
tpnt->next = scsi_devicelist; tpnt->next = scsi_devicelist;
scsi_devicelist = tpnt; scsi_devicelist = tpnt;
up_write(&scsi_devicelist_mutex);
tpnt->scsi_driverfs_driver.name = (char *)tpnt->tag; tpnt->scsi_driverfs_driver.name = (char *)tpnt->tag;
tpnt->scsi_driverfs_driver.bus = &scsi_driverfs_bus_type; tpnt->scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
...@@ -2006,18 +2098,10 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) ...@@ -2006,18 +2098,10 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
for (SDpnt = shpnt->host_queue; SDpnt; for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) { SDpnt = SDpnt->next) {
if (tpnt->detect) if (tpnt->detect)
SDpnt->attached += (*tpnt->detect) (SDpnt); (*tpnt->detect) (SDpnt);
} }
} }
/*
* If any of the devices would match this driver, then perform the
* init function.
*/
if (tpnt->init && tpnt->dev_noticed)
if ((*tpnt->init) ())
return 1;
/* /*
* Now actually connect the devices to the new driver. * Now actually connect the devices to the new driver.
*/ */
...@@ -2025,22 +2109,14 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt) ...@@ -2025,22 +2109,14 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
shpnt = scsi_host_get_next(shpnt)) { shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt; for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) { SDpnt = SDpnt->next) {
scsi_build_commandblocks(SDpnt);
if (SDpnt->current_queue_depth == 0) {
out_of_space = 1;
continue;
}
if (tpnt->attach) if (tpnt->attach)
/*
* XXX check result when the upper level
* attach return values are fixed, and
* stop attaching on failure.
*/
(*tpnt->attach) (SDpnt); (*tpnt->attach) (SDpnt);
/*
* If this driver attached to the device, and don't have any
* command blocks for this device, allocate some.
*/
if (SDpnt->attached)
SDpnt->online = TRUE;
else
scsi_release_commandblocks(SDpnt);
} }
} }
...@@ -2080,22 +2156,12 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt) ...@@ -2080,22 +2156,12 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
SDpnt = SDpnt->next) { SDpnt = SDpnt->next) {
if (tpnt->detach) if (tpnt->detach)
(*tpnt->detach) (SDpnt); (*tpnt->detach) (SDpnt);
if (SDpnt->attached == 0) {
SDpnt->online = FALSE;
/*
* Nobody is using this device any more. Free all of the
* command structures.
*/
if (shpnt->hostt->slave_detach)
(*shpnt->hostt->slave_detach) (SDpnt);
scsi_release_commandblocks(SDpnt);
}
} }
} }
/* /*
* Extract the template from the linked list. * Extract the template from the linked list.
*/ */
down_write(&scsi_devicelist_mutex);
spnt = scsi_devicelist; spnt = scsi_devicelist;
prev_spnt = NULL; prev_spnt = NULL;
while (spnt != tpnt) { while (spnt != tpnt) {
...@@ -2106,6 +2172,7 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt) ...@@ -2106,6 +2172,7 @@ int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
scsi_devicelist = tpnt->next; scsi_devicelist = tpnt->next;
else else
prev_spnt->next = spnt->next; prev_spnt->next = spnt->next;
up_write(&scsi_devicelist_mutex);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
unlock_kernel(); unlock_kernel();
......
...@@ -466,6 +466,8 @@ extern void scsi_bottom_half_handler(void); ...@@ -466,6 +466,8 @@ extern void scsi_bottom_half_handler(void);
extern void scsi_release_commandblocks(Scsi_Device * SDpnt); extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
extern void scsi_build_commandblocks(Scsi_Device * SDpnt); extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
extern int scsi_slave_attach(struct scsi_device *sdev);
extern void scsi_slave_detach(struct scsi_device *sdev);
extern void scsi_done(Scsi_Cmnd * SCpnt); extern void scsi_done(Scsi_Cmnd * SCpnt);
extern void scsi_finish_command(Scsi_Cmnd *); extern void scsi_finish_command(Scsi_Cmnd *);
extern int scsi_retry_command(Scsi_Cmnd *); extern int scsi_retry_command(Scsi_Cmnd *);
...@@ -478,6 +480,9 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, ...@@ -478,6 +480,9 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
int timeout, int retries); int timeout, int retries);
extern int scsi_dev_init(void); extern int scsi_dev_init(void);
extern int scsi_mlqueue_insert(struct scsi_cmnd *, int); extern int scsi_mlqueue_insert(struct scsi_cmnd *, int);
extern void scsi_detect_device(struct scsi_device *);
extern int scsi_attach_device(struct scsi_device *);
extern void scsi_detach_device(struct scsi_device *);
/* /*
* Newer request-based interfaces. * Newer request-based interfaces.
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* forked for lk 2.5 series [20011216, 20020101] * forked for lk 2.5 series [20011216, 20020101]
* use vmalloc() more inquiry+mode_sense [20020302] * use vmalloc() more inquiry+mode_sense [20020302]
* add timers for delayed responses [20020721] * add timers for delayed responses [20020721]
* Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -49,7 +50,7 @@ ...@@ -49,7 +50,7 @@
#include "scsi_debug.h" #include "scsi_debug.h"
static const char * scsi_debug_version_str = "Version: 1.62 (20020812)"; static const char * scsi_debug_version_str = "Version: 1.63 (20021103)";
#define DRIVERFS_SUPPORT 1 /* comment out whole line to disable */ #define DRIVERFS_SUPPORT 1 /* comment out whole line to disable */
...@@ -60,9 +61,8 @@ static const char * scsi_debug_version_str = "Version: 1.62 (20020812)"; ...@@ -60,9 +61,8 @@ static const char * scsi_debug_version_str = "Version: 1.62 (20020812)";
#ifndef SCSI_CMD_WRITE_16 #ifndef SCSI_CMD_WRITE_16
#define SCSI_CMD_WRITE_16 0x8a #define SCSI_CMD_WRITE_16 0x8a
#endif #endif
#ifndef REPORT_LUNS
#define REPORT_LUNS 0xa0 #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
#endif
/* A few options that we want selected */ /* A few options that we want selected */
#define DEF_NR_FAKE_DEVS 1 #define DEF_NR_FAKE_DEVS 1
...@@ -70,6 +70,8 @@ static const char * scsi_debug_version_str = "Version: 1.62 (20020812)"; ...@@ -70,6 +70,8 @@ static const char * scsi_debug_version_str = "Version: 1.62 (20020812)";
#define DEF_FAKE_BLK0 0 #define DEF_FAKE_BLK0 0
#define DEF_EVERY_NTH 100 #define DEF_EVERY_NTH 100
#define DEF_DELAY 1 #define DEF_DELAY 1
#define DEF_MAX_LUNS 2
#define DEF_SCSI_LEVEL 3
#define DEF_OPTS 0 #define DEF_OPTS 0
#define SCSI_DEBUG_OPT_NOISE 1 #define SCSI_DEBUG_OPT_NOISE 1
...@@ -83,8 +85,11 @@ static int scsi_debug_opts = DEF_OPTS; ...@@ -83,8 +85,11 @@ static int scsi_debug_opts = DEF_OPTS;
static int scsi_debug_every_nth = DEF_EVERY_NTH; static int scsi_debug_every_nth = DEF_EVERY_NTH;
static int scsi_debug_cmnd_count = 0; static int scsi_debug_cmnd_count = 0;
static int scsi_debug_delay = DEF_DELAY; static int scsi_debug_delay = DEF_DELAY;
static int scsi_debug_max_luns = DEF_MAX_LUNS;
static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
/* This assumes one lun used per allocated target id */
#define N_HEAD 8 #define N_HEAD 8
#define N_SECTOR 32 #define N_SECTOR 32
#define DEV_READONLY(TGT) (0) #define DEV_READONLY(TGT) (0)
...@@ -118,7 +123,7 @@ struct sdebug_dev_info { ...@@ -118,7 +123,7 @@ struct sdebug_dev_info {
}; };
static struct sdebug_dev_info * devInfop; static struct sdebug_dev_info * devInfop;
typedef void (* done_funct_t) (Scsi_Cmnd *); typedef void (* done_funct_t) (struct scsi_cmnd *);
struct sdebug_queued_cmd { struct sdebug_queued_cmd {
int in_use; int in_use;
...@@ -131,7 +136,7 @@ static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; ...@@ -131,7 +136,7 @@ static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
static unsigned char * fake_storep; /* ramdisk storage */ static unsigned char * fake_storep; /* ramdisk storage */
static unsigned char broken_buff[SDEBUG_SENSE_LEN]; static unsigned char spare_buff[SDEBUG_SENSE_LEN];
static int num_aborts = 0; static int num_aborts = 0;
static int num_dev_resets = 0; static int num_dev_resets = 0;
...@@ -151,17 +156,18 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, ...@@ -151,17 +156,18 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
static int resp_mode_sense(unsigned char * cmd, int target, static int resp_mode_sense(unsigned char * cmd, int target,
unsigned char * buff, int bufflen, unsigned char * buff, int bufflen,
struct sdebug_dev_info * devip); struct sdebug_dev_info * devip);
static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
int num, struct sdebug_dev_info * devip); int num, struct sdebug_dev_info * devip);
static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
struct sdebug_dev_info * devip); int num, struct sdebug_dev_info * devip);
static int resp_report_luns(unsigned char * cmd, unsigned char * buff, static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
int bufflen, struct sdebug_dev_info * devip); int bufflen, struct sdebug_dev_info * devip);
static void timer_intr_handler(unsigned long); static void timer_intr_handler(unsigned long);
static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd); static struct sdebug_dev_info * devInfoReg(struct scsi_cmnd *scmd);
static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
int asc, int asq, int inbandLen); int asc, int asq, int inbandLen);
static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip); static int check_reset(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
static int schedule_resp(struct scsi_cmnd * cmnd, static int schedule_resp(struct scsi_cmnd * cmnd,
struct sdebug_dev_info * devip, struct sdebug_dev_info * devip,
done_funct_t done, int scsi_result, int delta_jiff); done_funct_t done, int scsi_result, int delta_jiff);
...@@ -188,7 +194,7 @@ static unsigned char * scatg2virt(const struct scatterlist * sclp) ...@@ -188,7 +194,7 @@ static unsigned char * scatg2virt(const struct scatterlist * sclp)
} }
static static
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
{ {
unsigned char *cmd = (unsigned char *) SCpnt->cmnd; unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
int block; int block;
...@@ -215,8 +221,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) ...@@ -215,8 +221,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
else else
buff = (unsigned char *) SCpnt->request_buffer; buff = (unsigned char *) SCpnt->request_buffer;
if (NULL == buff) { if (NULL == buff) {
printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n"); buff = spare_buff; /* assume cmd moves no data */
buff = broken_buff; /* just point at dummy */
bufflen = SDEBUG_SENSE_LEN; bufflen = SDEBUG_SENSE_LEN;
} }
...@@ -226,11 +231,11 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) ...@@ -226,11 +231,11 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
return schedule_resp(SCpnt, NULL, done, 0, 0); return schedule_resp(SCpnt, NULL, done, 0, 0);
} }
if (SCpnt->lun != 0) if (SCpnt->lun >= scsi_debug_max_luns)
return schedule_resp(SCpnt, NULL, done, return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0); DID_NO_CONNECT << 16, 0);
#if 0 #if 0
printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n", printk(KERN_INFO "sdebug:qc: host_no=%u, id=%u, sdp=%p, cmd=0x%x\n",
(int)SCpnt->device->host->host_no, (int)SCpnt->device->id, (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
SCpnt->device, (int)*cmd); SCpnt->device, (int)*cmd);
#endif #endif
...@@ -248,9 +253,6 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) ...@@ -248,9 +253,6 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
switch (*cmd) { switch (*cmd) {
case INQUIRY: /* mandatory */ case INQUIRY: /* mandatory */
/* assume INQUIRY called first so setup max_cmd_len */
if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
errsts = resp_inquiry(cmd, target, buff, bufflen, devip); errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
break; break;
case REQUEST_SENSE: /* mandatory */ case REQUEST_SENSE: /* mandatory */
...@@ -380,6 +382,9 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) ...@@ -380,6 +382,9 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
case MODE_SENSE_10: case MODE_SENSE_10:
errsts = resp_mode_sense(cmd, target, buff, bufflen, devip); errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
break; break;
case SYNCHRONIZE_CACHE:
memset(buff, 0, bufflen);
break;
default: default:
#if 0 #if 0
printk(KERN_INFO "scsi_debug: Unsupported command, " printk(KERN_INFO "scsi_debug: Unsupported command, "
...@@ -394,7 +399,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done) ...@@ -394,7 +399,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay); return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
} }
static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg) static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void *arg)
{ {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
...@@ -403,7 +408,7 @@ static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg) ...@@ -403,7 +408,7 @@ static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
/* return -ENOTTY; // correct return but upsets fdisk */ /* return -ENOTTY; // correct return but upsets fdisk */
} }
static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip) static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
{ {
if (devip->reset) { if (devip->reset) {
devip->reset = 0; devip->reset = 0;
...@@ -474,8 +479,8 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, ...@@ -474,8 +479,8 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
int dev_id_num, len; int dev_id_num, len;
char dev_id_str[6]; char dev_id_str[6];
dev_id_num = ((devip->host->host_no + 1) * 1000) + dev_id_num = ((devip->host->host_no + 1) * 2000) +
devip->target; (devip->target * 1000) + devip->lun;
len = snprintf(dev_id_str, 6, "%d", dev_id_num); len = snprintf(dev_id_str, 6, "%d", dev_id_num);
len = (len > 6) ? 6 : len; len = (len > 6) ? 6 : len;
if (0 == cmd[2]) { /* supported vital product data pages */ if (0 == cmd[2]) { /* supported vital product data pages */
...@@ -501,7 +506,7 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, ...@@ -501,7 +506,7 @@ static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
} }
/* drops through here for a standard inquiry */ /* drops through here for a standard inquiry */
arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
arr[2] = 3; /* claim SCSI 3 */ arr[2] = scsi_debug_scsi_level;
arr[4] = SDEBUG_LONG_INQ_SZ - 5; arr[4] = SDEBUG_LONG_INQ_SZ - 5;
arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
memcpy(&arr[8], vendor_id, 8); memcpy(&arr[8], vendor_id, 8);
...@@ -643,6 +648,7 @@ static int resp_mode_sense(unsigned char * cmd, int target, ...@@ -643,6 +648,7 @@ static int resp_mode_sense(unsigned char * cmd, int target,
case 0x3f: /* Read all Mode pages */ case 0x3f: /* Read all Mode pages */
len = resp_err_recov_pg(ap, pcontrol, target); len = resp_err_recov_pg(ap, pcontrol, target);
len += resp_disconnect_pg(ap + len, pcontrol, target); len += resp_disconnect_pg(ap + len, pcontrol, target);
len += resp_format_pg(ap + len, pcontrol, target);
len += resp_caching_pg(ap + len, pcontrol, target); len += resp_caching_pg(ap + len, pcontrol, target);
len += resp_ctrl_m_pg(ap + len, pcontrol, target); len += resp_ctrl_m_pg(ap + len, pcontrol, target);
offset += len; offset += len;
...@@ -662,8 +668,8 @@ static int resp_mode_sense(unsigned char * cmd, int target, ...@@ -662,8 +668,8 @@ static int resp_mode_sense(unsigned char * cmd, int target,
return 0; return 0;
} }
static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
struct sdebug_dev_info * devip) int num, struct sdebug_dev_info * devip)
{ {
unsigned char *buff = (unsigned char *) SCpnt->request_buffer; unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
int nbytes, sgcount; int nbytes, sgcount;
...@@ -711,8 +717,8 @@ static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, ...@@ -711,8 +717,8 @@ static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
return 0; return 0;
} }
static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
struct sdebug_dev_info * devip) int num, struct sdebug_dev_info * devip)
{ {
unsigned char *buff = (unsigned char *) SCpnt->request_buffer; unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
int nbytes, sgcount; int nbytes, sgcount;
...@@ -756,8 +762,9 @@ static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, ...@@ -756,8 +762,9 @@ static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
static int resp_report_luns(unsigned char * cmd, unsigned char * buff, static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
int bufflen, struct sdebug_dev_info * devip) int bufflen, struct sdebug_dev_info * devip)
{ {
unsigned int alloc_len; unsigned int alloc_len, lun_cnt, i;
int select_report = (int)cmd[2]; int select_report = (int)cmd[2];
ScsiLun *one_lun;
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
if ((alloc_len < 16) || (select_report > 2)) { if ((alloc_len < 16) || (select_report > 2)) {
...@@ -765,8 +772,13 @@ static int resp_report_luns(unsigned char * cmd, unsigned char * buff, ...@@ -765,8 +772,13 @@ static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
} }
if (bufflen > 3) { if (bufflen > 3) {
lun_cnt = min((int)(bufflen / sizeof(ScsiLun)),
(int)scsi_debug_max_luns);
memset(buff, 0, bufflen); memset(buff, 0, bufflen);
buff[3] = 8; buff[3] = 8 * lun_cnt;
one_lun = (ScsiLun*) &buff[0];
for (i = 0; i < lun_cnt; i++)
one_lun[i].scsi_lun[1] = i;
} }
return 0; return 0;
} }
...@@ -798,12 +810,13 @@ static void timer_intr_handler(unsigned long indx) ...@@ -798,12 +810,13 @@ static void timer_intr_handler(unsigned long indx)
} }
static int initialized = 0; static int initialized = 0;
static int num_present = 0; static int num_hosts_present = 0;
static const char * sdebug_proc_name = "scsi_debug"; static const char * sdebug_proc_name = "scsi_debug";
static int scsi_debug_detect(Scsi_Host_Template * tpnt) static int scsi_debug_detect(struct SHT * tpnt)
{ {
int k, sz; int k, sz;
struct Scsi_Host * hpnt;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: detect\n"); printk(KERN_INFO "scsi_debug: detect\n");
...@@ -813,7 +826,7 @@ static int scsi_debug_detect(Scsi_Host_Template * tpnt) ...@@ -813,7 +826,7 @@ static int scsi_debug_detect(Scsi_Host_Template * tpnt)
devInfop = vmalloc(sz); devInfop = vmalloc(sz);
if (NULL == devInfop) { if (NULL == devInfop) {
printk(KERN_ERR "scsi_debug_detect: out of " printk(KERN_ERR "scsi_debug_detect: out of "
"memory, 0.5\n"); "memory\n");
return 0; return 0;
} }
memset(devInfop, 0, sz); memset(devInfop, 0, sz);
...@@ -821,28 +834,31 @@ static int scsi_debug_detect(Scsi_Host_Template * tpnt) ...@@ -821,28 +834,31 @@ static int scsi_debug_detect(Scsi_Host_Template * tpnt)
fake_storep = vmalloc(sz); fake_storep = vmalloc(sz);
if (NULL == fake_storep) { if (NULL == fake_storep) {
printk(KERN_ERR "scsi_debug_detect: out of memory" printk(KERN_ERR "scsi_debug_detect: out of memory"
", 0\n"); ", 1\n");
return 0; return 0;
} }
memset(fake_storep, 0, sz); memset(fake_storep, 0, sz);
init_all_queued(); init_all_queued();
#ifdef DRIVERFS_SUPPORT
sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sdebug_driverfs_driver);
do_create_driverfs_files();
#endif
tpnt->proc_name = (char *)sdebug_proc_name; tpnt->proc_name = (char *)sdebug_proc_name;
for (num_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) { for (num_hosts_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
if (NULL == scsi_register(tpnt, 0)) if ((hpnt = scsi_register(tpnt, 0)) == NULL)
printk(KERN_ERR "scsi_debug_detect: " printk(KERN_ERR "scsi_debug_detect: "
"scsi_register failed k=%d\n", k); "scsi_register failed k=%d\n", k);
else else {
++num_present; hpnt->max_lun = scsi_debug_max_luns;
} ++num_hosts_present;
#ifdef DRIVERFS_SUPPORT }
if (num_present) {
sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sdebug_driverfs_driver);
do_create_driverfs_files();
} }
#endif if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
return num_present; printk(KERN_INFO "scsi_debug: ... built %d host(s)\n",
num_hosts_present);
return num_hosts_present;
} else { } else {
printk(KERN_WARNING "scsi_debug_detect: called again\n"); printk(KERN_WARNING "scsi_debug_detect: called again\n");
return 0; return 0;
...@@ -854,11 +870,15 @@ static int num_releases = 0; ...@@ -854,11 +870,15 @@ static int num_releases = 0;
static int scsi_debug_release(struct Scsi_Host * hpnt) static int scsi_debug_release(struct Scsi_Host * hpnt)
{ {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) int host_no = hpnt->host_no;
printk(KERN_INFO "scsi_debug: release\n");
stop_all_queued(); if (++num_releases == num_hosts_present) {
scsi_unregister(hpnt); if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
if (++num_releases == num_present) { printk(KERN_INFO "scsi_debug: [last] release, "
"host_no=%u\n", host_no);
num_releases = 0;
initialized = 0;
stop_all_queued();
#ifdef DRIVERFS_SUPPORT #ifdef DRIVERFS_SUPPORT
do_remove_driverfs_files(); do_remove_driverfs_files();
driver_unregister(&sdebug_driverfs_driver); driver_unregister(&sdebug_driverfs_driver);
...@@ -866,14 +886,65 @@ static int scsi_debug_release(struct Scsi_Host * hpnt) ...@@ -866,14 +886,65 @@ static int scsi_debug_release(struct Scsi_Host * hpnt)
vfree(fake_storep); vfree(fake_storep);
vfree(devInfop); vfree(devInfop);
} }
else {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: release, host_no=%u\n",
host_no);
}
scsi_unregister(hpnt);
return 0; return 0;
} }
static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd) static int scsi_debug_slave_attach(struct scsi_device * sdp)
{ {
int k; int k;
struct sdebug_dev_info * devip; struct sdebug_dev_info * devip;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: slave_attach <%u %u %u %u>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
for (k = 0; k < scsi_debug_num_devs; ++k) {
devip = &devInfop[k];
if ((devip->channel == sdp->channel) &&
(devip->target == sdp->id) &&
(devip->lun == sdp->lun) &&
(devip->host == sdp->host)) {
sdp->hostdata = devip;
break;
}
}
if (sdp->host->cmd_per_lun)
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
sdp->host->cmd_per_lun);
return 0;
}
static void scsi_debug_slave_detach(struct scsi_device * sdp)
{
struct sdebug_dev_info * devip =
(struct sdebug_dev_info *)sdp->hostdata;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: slave_detach <%u %u %u %u>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (devip) {
/* make this slot avaliable for re-use */
memset(devip, 0, sizeof(struct sdebug_dev_info));
sdp->hostdata = NULL;
}
}
static struct sdebug_dev_info * devInfoReg(struct scsi_cmnd *scmd)
{
int k;
struct scsi_device * sdp = scmd->device;
struct sdebug_dev_info * devip =
(struct sdebug_dev_info *)sdp->hostdata;
if (devip)
return devip;
for (k = 0; k < scsi_debug_num_devs; ++k) { for (k = 0; k < scsi_debug_num_devs; ++k) {
devip = &devInfop[k]; devip = &devInfop[k];
if ((devip->channel == scmd->channel) && if ((devip->channel == scmd->channel) &&
...@@ -915,7 +986,7 @@ static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, ...@@ -915,7 +986,7 @@ static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
sbuff[13] = asq; sbuff[13] = asq;
} }
static int scsi_debug_abort(Scsi_Cmnd * SCpnt) static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
{ {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: abort\n"); printk(KERN_INFO "scsi_debug: abort\n");
...@@ -938,7 +1009,7 @@ static int scsi_debug_biosparam(struct scsi_device *sdev, ...@@ -938,7 +1009,7 @@ static int scsi_debug_biosparam(struct scsi_device *sdev,
return 0; return 0;
} }
static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
{ {
struct sdebug_dev_info * devip; struct sdebug_dev_info * devip;
...@@ -953,9 +1024,9 @@ static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt) ...@@ -953,9 +1024,9 @@ static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
return SUCCESS; return SUCCESS;
} }
static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
{ {
Scsi_Device * sdp; struct scsi_device * sdp;
struct Scsi_Host * hp; struct Scsi_Host * hp;
int k; int k;
...@@ -971,7 +1042,7 @@ static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt) ...@@ -971,7 +1042,7 @@ static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
return SUCCESS; return SUCCESS;
} }
static int scsi_debug_host_reset(Scsi_Cmnd * SCpnt) static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
{ {
int k; int k;
...@@ -1048,11 +1119,18 @@ static int schedule_resp(struct scsi_cmnd * cmnd, ...@@ -1048,11 +1119,18 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
{ {
int k, num; int k, num;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
printk(KERN_INFO "scsi_debug: cmd "); printk(KERN_INFO "scsi_debug: cmd ");
for (k = 0, num = cmnd->cmd_len; k < num; ++k) for (k = 0, num = cmnd->cmd_len; k < num; ++k)
printk("%02x ", (int)cmnd->cmnd[k]); printk("%02x ", (int)cmnd->cmnd[k]);
printk("result=0x%x\n", scsi_result); printk("\n");
if (scsi_result) {
struct scsi_device * sdp = cmnd->device;
printk(KERN_INFO "scsi_debug: ... <%u %u %u %u> "
"non-zero result=0x%x\n", sdp->host->host_no,
sdp->channel, sdp->id, sdp->lun, scsi_result);
}
} }
if (cmnd && devip) { if (cmnd && devip) {
/* simulate autosense by this driver */ /* simulate autosense by this driver */
...@@ -1113,6 +1191,38 @@ static int __init num_devs_setup(char *str) ...@@ -1113,6 +1191,38 @@ static int __init num_devs_setup(char *str)
} }
__setup("scsi_debug_num_devs=", num_devs_setup); __setup("scsi_debug_num_devs=", num_devs_setup);
static int __init max_luns_setup(char *str)
{
int tmp;
if (get_option(&str, &tmp) == 1) {
if (tmp > 0)
scsi_debug_max_luns = tmp;
return 1;
} else {
printk(KERN_INFO "scsi_debug_max_luns: usage scsi_debug_max_luns=<n> "
"(<n> is a postive integer (def=2))\n");
return 0;
}
}
__setup("scsi_debug_max_luns=", max_luns_setup);
static int __init scsi_level_setup(char *str)
{
int tmp;
if (get_option(&str, &tmp) == 1) {
if (tmp > 0)
scsi_debug_scsi_level = tmp;
return 1;
} else {
printk(KERN_INFO "scsi_debug_scsi_level: usage "
"scsi_debug_scsi_level=<n> (<n> is 1..4 (def=3))\n");
return 0;
}
}
__setup("scsi_debug_scsi_level=", scsi_level_setup);
static int __init dev_size_mb_setup(char *str) static int __init dev_size_mb_setup(char *str)
{ {
int tmp; int tmp;
...@@ -1186,6 +1296,10 @@ MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); ...@@ -1186,6 +1296,10 @@ MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
MODULE_DESCRIPTION("SCSI debug adapter driver"); MODULE_DESCRIPTION("SCSI debug adapter driver");
MODULE_PARM(scsi_debug_num_devs, "i"); MODULE_PARM(scsi_debug_num_devs, "i");
MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate"); MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
MODULE_PARM(scsi_debug_max_luns, "i");
MODULE_PARM_DESC(scsi_debug_max_luns, "number of SCSI LUNs per target to simulate");
MODULE_PARM(scsi_debug_scsi_level, "i");
MODULE_PARM_DESC(scsi_debug_scsi_level, "SCSI level to simulate");
MODULE_PARM(scsi_debug_dev_size_mb, "i"); MODULE_PARM(scsi_debug_dev_size_mb, "i");
MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs"); MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
MODULE_PARM(scsi_debug_opts, "i"); MODULE_PARM(scsi_debug_opts, "i");
...@@ -1237,13 +1351,15 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset, ...@@ -1237,13 +1351,15 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
"num_devs=%d, shared (ram) size=%d MB, opts=0x%x, " "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
"every_nth=%d(curr:%d)\n" "every_nth=%d(curr:%d)\n"
"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d, " "delay=%d, max_luns=%d, scsi_level=%d\n"
"delay=%d\nnumber of aborts=%d, device_reset=%d, bus_resets=%d, " "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
"number of aborts=%d, device_reset=%d, bus_resets=%d, "
"host_resets=%d\n", "host_resets=%d\n",
scsi_debug_version_str, scsi_debug_num_devs, scsi_debug_version_str, scsi_debug_num_devs,
scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
scsi_debug_cmnd_count, scsi_debug_cmnd_count, scsi_debug_delay,
SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, scsi_debug_delay, scsi_debug_max_luns, scsi_debug_scsi_level,
SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR,
num_aborts, num_dev_resets, num_bus_resets, num_host_resets); num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
if (pos < offset) { if (pos < offset) {
len = 0; len = 0;
...@@ -1253,8 +1369,7 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset, ...@@ -1253,8 +1369,7 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
len -= (offset - begin); len -= (offset - begin);
if (len > length) if (len > length)
len = length; len = length;
return len;
return (len);
} }
#ifdef DRIVERFS_SUPPORT #ifdef DRIVERFS_SUPPORT
...@@ -1280,7 +1395,6 @@ static ssize_t sdebug_delay_write(struct device_driver * ddp, ...@@ -1280,7 +1395,6 @@ static ssize_t sdebug_delay_write(struct device_driver * ddp,
} }
return -EINVAL; return -EINVAL;
} }
DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_read, DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_read,
sdebug_delay_write) sdebug_delay_write)
...@@ -1312,7 +1426,6 @@ static ssize_t sdebug_opts_write(struct device_driver * ddp, ...@@ -1312,7 +1426,6 @@ static ssize_t sdebug_opts_write(struct device_driver * ddp,
scsi_debug_opts = opts; scsi_debug_opts = opts;
return count; return count;
} }
DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_read, DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_read,
sdebug_opts_write) sdebug_opts_write)
...@@ -1321,18 +1434,53 @@ static ssize_t sdebug_num_devs_read(struct device_driver * ddp, char * buf, ...@@ -1321,18 +1434,53 @@ static ssize_t sdebug_num_devs_read(struct device_driver * ddp, char * buf,
{ {
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_num_devs); return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_num_devs);
} }
DRIVER_ATTR(num_devs, S_IRUGO, sdebug_num_devs_read, NULL) DRIVER_ATTR(num_devs, S_IRUGO, sdebug_num_devs_read, NULL)
static ssize_t sdebug_dev_size_mb_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_dev_size_mb);
}
DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_read, NULL)
static ssize_t sdebug_every_nth_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_every_nth);
}
DRIVER_ATTR(every_nth, S_IRUGO, sdebug_every_nth_read, NULL)
static ssize_t sdebug_max_luns_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_max_luns);
}
DRIVER_ATTR(max_luns, S_IRUGO, sdebug_max_luns_read, NULL)
static ssize_t sdebug_scsi_level_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_scsi_level);
}
DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_read, NULL)
static void do_create_driverfs_files() static void do_create_driverfs_files()
{ {
driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs); driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
} }
static void do_remove_driverfs_files() static void do_remove_driverfs_files()
{ {
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
......
...@@ -3,17 +3,20 @@ ...@@ -3,17 +3,20 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
static int scsi_debug_detect(Scsi_Host_Template *); static int scsi_debug_detect(struct SHT *);
static int scsi_debug_slave_attach(struct scsi_device *);
static void scsi_debug_slave_detach(struct scsi_device *);
static int scsi_debug_release(struct Scsi_Host *); static int scsi_debug_release(struct Scsi_Host *);
/* static int scsi_debug_command(Scsi_Cmnd *); */ /* static int scsi_debug_command(struct scsi_cmnd *); */
static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int scsi_debug_queuecommand(struct scsi_cmnd *,
static int scsi_debug_ioctl(Scsi_Device *, int, void *); void (*done) (struct scsi_cmnd *));
static int scsi_debug_ioctl(struct scsi_device *, int, void *);
static int scsi_debug_biosparam(struct scsi_device *, struct block_device *, static int scsi_debug_biosparam(struct scsi_device *, struct block_device *,
sector_t, int[]); sector_t, int[]);
static int scsi_debug_abort(Scsi_Cmnd *); static int scsi_debug_abort(struct scsi_cmnd *);
static int scsi_debug_bus_reset(Scsi_Cmnd *); static int scsi_debug_bus_reset(struct scsi_cmnd *);
static int scsi_debug_device_reset(Scsi_Cmnd *); static int scsi_debug_device_reset(struct scsi_cmnd *);
static int scsi_debug_host_reset(Scsi_Cmnd *); static int scsi_debug_host_reset(struct scsi_cmnd *);
static int scsi_debug_proc_info(char *, char **, off_t, int, int, int); static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
static const char * scsi_debug_info(struct Scsi_Host *); static const char * scsi_debug_info(struct Scsi_Host *);
...@@ -33,6 +36,8 @@ static Scsi_Host_Template driver_template = { ...@@ -33,6 +36,8 @@ static Scsi_Host_Template driver_template = {
.name = "SCSI DEBUG", .name = "SCSI DEBUG",
.info = scsi_debug_info, .info = scsi_debug_info,
.detect = scsi_debug_detect, .detect = scsi_debug_detect,
.slave_attach = scsi_debug_slave_attach,
.slave_detach = scsi_debug_slave_detach,
.release = scsi_debug_release, .release = scsi_debug_release,
.ioctl = scsi_debug_ioctl, .ioctl = scsi_debug_ioctl,
.queuecommand = scsi_debug_queuecommand, .queuecommand = scsi_debug_queuecommand,
......
...@@ -352,34 +352,12 @@ int proc_info(char * buffer, char ** start, off_t offset, ...@@ -352,34 +352,12 @@ int proc_info(char * buffer, char ** start, off_t offset,
* Locks: lock_kernel() active on entry and expected to be active * Locks: lock_kernel() active on entry and expected to be active
* on return. * on return.
* *
* Notes: Invoked from mid level's scsi_unregister_host(). When a * Notes: Invoked from mid level's scsi_unregister_host().
* host is being unregistered the mid level does not bother to
* call revoke() on the devices it controls.
* This function should call scsi_unregister(shp) [found in hosts.c] * This function should call scsi_unregister(shp) [found in hosts.c]
* prior to returning. * prior to returning.
**/ **/
int release(struct Scsi_Host * shp); int release(struct Scsi_Host * shp);
/**
* revoke - indicate disinterest in a scsi device
* @sdp: host template for this driver.
*
* Return value ignored.
*
* Required: no
*
* Locks: none held
*
* Notes: Called when "scsi remove-single-device <h> <b> <t> <l>"
* is written to /proc/scsi/scsi to indicate the device is no longer
* required. It is called after the upper level drivers have detached
* this device and before the device name (e.g. /dev/sdc) is
* unregistered and the resources associated with it are freed.
**/
int revoke(Scsi_device * sdp);
/** /**
* select_queue_depths - calculate allowable number of scsi commands * select_queue_depths - calculate allowable number of scsi commands
* that can be queued on each device (disk) * that can be queued on each device (disk)
......
...@@ -1322,7 +1322,6 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1322,7 +1322,6 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
Scsi_Request *sreq, char *inq_result, int *bflags) Scsi_Request *sreq, char *inq_result, int *bflags)
{ {
Scsi_Device *sdev; Scsi_Device *sdev;
struct Scsi_Device_Template *sdt;
char devname[64]; char devname[64];
extern devfs_handle_t scsi_devfs_handle; extern devfs_handle_t scsi_devfs_handle;
...@@ -1479,18 +1478,7 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1479,18 +1478,7 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
* function */ * function */
sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED; sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
for (sdt = scsi_devicelist; sdt; sdt = sdt->next) scsi_detect_device(sdev);
if (sdt->detect)
sdev->attached += (*sdt->detect) (sdev);
if (sdev->host->hostt->slave_attach != NULL) {
if (sdev->host->hostt->slave_attach(sdev) != 0) {
printk(KERN_INFO "%s: scsi_add_lun: failed low level driver attach, setting device offline", devname);
sdev->online = FALSE;
}
} else if(sdev->host->cmd_per_lun) {
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
if (sdevnew != NULL) if (sdevnew != NULL)
*sdevnew = sdev; *sdevnew = sdev;
...@@ -2010,7 +1998,6 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel, ...@@ -2010,7 +1998,6 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
uint id, uint lun) uint id, uint lun)
{ {
Scsi_Device *sdevscan, *sdev = NULL; Scsi_Device *sdevscan, *sdev = NULL;
struct Scsi_Device_Template *sdt;
int res; int res;
if ((channel > shost->max_channel) || (id >= shost->max_id) || if ((channel > shost->max_channel) || (id >= shost->max_id) ||
...@@ -2028,24 +2015,7 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel, ...@@ -2028,24 +2015,7 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
if (res != SCSI_SCAN_LUN_PRESENT) if (res != SCSI_SCAN_LUN_PRESENT)
return; return;
BUG_ON(sdev == NULL); scsi_attach_device(sdev);
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
return;
}
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->init && sdt->dev_noticed)
(*sdt->init) ();
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->attach)
(*sdt->attach) (sdev);
if (!sdev->attached)
scsi_release_commandblocks(sdev);
} }
/** /**
......
...@@ -32,6 +32,8 @@ EXPORT_SYMBOL(scsi_register_device); ...@@ -32,6 +32,8 @@ EXPORT_SYMBOL(scsi_register_device);
EXPORT_SYMBOL(scsi_unregister_device); EXPORT_SYMBOL(scsi_unregister_device);
EXPORT_SYMBOL(scsi_register_host); EXPORT_SYMBOL(scsi_register_host);
EXPORT_SYMBOL(scsi_unregister_host); EXPORT_SYMBOL(scsi_unregister_host);
EXPORT_SYMBOL(scsi_add_host);
EXPORT_SYMBOL(scsi_remove_host);
EXPORT_SYMBOL(scsi_register); EXPORT_SYMBOL(scsi_register);
EXPORT_SYMBOL(scsi_unregister); EXPORT_SYMBOL(scsi_unregister);
EXPORT_SYMBOL(scsicam_bios_param); EXPORT_SYMBOL(scsicam_bios_param);
...@@ -80,6 +82,8 @@ EXPORT_SYMBOL(scsi_end_request); ...@@ -80,6 +82,8 @@ EXPORT_SYMBOL(scsi_end_request);
EXPORT_SYMBOL(scsi_register_blocked_host); EXPORT_SYMBOL(scsi_register_blocked_host);
EXPORT_SYMBOL(scsi_deregister_blocked_host); EXPORT_SYMBOL(scsi_deregister_blocked_host);
EXPORT_SYMBOL(scsi_slave_attach);
EXPORT_SYMBOL(scsi_slave_detach);
/* /*
* This symbol is for the highlevel drivers (e.g. sg) only. * This symbol is for the highlevel drivers (e.g. sg) only.
...@@ -92,7 +96,6 @@ EXPORT_SYMBOL(scsi_reset_provider); ...@@ -92,7 +96,6 @@ EXPORT_SYMBOL(scsi_reset_provider);
EXPORT_SYMBOL(scsi_host_get_next); EXPORT_SYMBOL(scsi_host_get_next);
EXPORT_SYMBOL(scsi_host_hn_get); EXPORT_SYMBOL(scsi_host_hn_get);
EXPORT_SYMBOL(scsi_host_put); EXPORT_SYMBOL(scsi_host_put);
EXPORT_SYMBOL(scsi_devicelist);
EXPORT_SYMBOL(scsi_device_types); EXPORT_SYMBOL(scsi_device_types);
/* /*
......
...@@ -83,6 +83,7 @@ struct scsi_disk { ...@@ -83,6 +83,7 @@ struct scsi_disk {
unsigned RCD : 1; /* state of disk RCD bit */ unsigned RCD : 1; /* state of disk RCD bit */
}; };
static int sd_nr_dev; /* XXX(hch) bad hack, we want a bitmap instead */
static LIST_HEAD(sd_devlist); static LIST_HEAD(sd_devlist);
static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED;
...@@ -106,7 +107,6 @@ static struct Scsi_Device_Template sd_template = { ...@@ -106,7 +107,6 @@ static struct Scsi_Device_Template sd_template = {
.name = "disk", .name = "disk",
.tag = "sd", .tag = "sd",
.scsi_type = TYPE_DISK, .scsi_type = TYPE_DISK,
.blk = 1,
.detect = sd_detect, .detect = sd_detect,
.attach = sd_attach, .attach = sd_attach,
.detach = sd_detach, .detach = sd_detach,
...@@ -1179,7 +1179,6 @@ static int sd_detect(struct scsi_device * sdp) ...@@ -1179,7 +1179,6 @@ static int sd_detect(struct scsi_device * sdp)
SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type)); SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type));
if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD) if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD)
return 0; return 0;
sd_template.dev_noticed++;
return 1; return 1;
} }
...@@ -1213,9 +1212,12 @@ static int sd_attach(struct scsi_device * sdp) ...@@ -1213,9 +1212,12 @@ static int sd_attach(struct scsi_device * sdp)
SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun)); sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
if (scsi_slave_attach(sdp))
goto out;
sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
if (!sdkp) if (!sdkp)
goto out; goto out_detach;
gd = alloc_disk(16); gd = alloc_disk(16);
if (!gd) if (!gd)
...@@ -1228,7 +1230,7 @@ static int sd_attach(struct scsi_device * sdp) ...@@ -1228,7 +1230,7 @@ static int sd_attach(struct scsi_device * sdp)
* XXX use find_first_zero_bit on it. This will happen at the * XXX use find_first_zero_bit on it. This will happen at the
* XXX same time template->nr_* goes away. --hch * XXX same time template->nr_* goes away. --hch
*/ */
dsk_nr = sd_template.nr_dev++; dsk_nr = sd_nr_dev++;
sdkp->device = sdp; sdkp->device = sdp;
sdkp->driver = &sd_template; sdkp->driver = &sd_template;
...@@ -1264,8 +1266,9 @@ static int sd_attach(struct scsi_device * sdp) ...@@ -1264,8 +1266,9 @@ static int sd_attach(struct scsi_device * sdp)
out_free: out_free:
kfree(sdkp); kfree(sdkp);
out_detach:
scsi_slave_detach(sdp);
out: out:
sdp->attached--;
return 1; return 1;
} }
...@@ -1313,9 +1316,8 @@ static void sd_detach(struct scsi_device * sdp) ...@@ -1313,9 +1316,8 @@ static void sd_detach(struct scsi_device * sdp)
sd_devlist_remove(sdkp); sd_devlist_remove(sdkp);
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
sdp->attached--; scsi_slave_detach(sdp);
sd_template.dev_noticed--; sd_nr_dev--;
sd_template.nr_dev--;
put_disk(sdkp->disk); put_disk(sdkp->disk);
kfree(sdkp); kfree(sdkp);
} }
......
...@@ -110,7 +110,6 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF; ...@@ -110,7 +110,6 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
static int sg_init(void);
static int sg_attach(Scsi_Device *); static int sg_attach(Scsi_Device *);
static int sg_detect(Scsi_Device *); static int sg_detect(Scsi_Device *);
static void sg_detach(Scsi_Device *); static void sg_detach(Scsi_Device *);
...@@ -126,7 +125,6 @@ static struct Scsi_Device_Template sg_template = { ...@@ -126,7 +125,6 @@ static struct Scsi_Device_Template sg_template = {
.tag = "sg", .tag = "sg",
.scsi_type = 0xff, .scsi_type = 0xff,
.detect = sg_detect, .detect = sg_detect,
.init = sg_init,
.attach = sg_attach, .attach = sg_attach,
.detach = sg_detach .detach = sg_detach
}; };
...@@ -235,6 +233,9 @@ static int sg_last_dev(void); ...@@ -235,6 +233,9 @@ static int sg_last_dev(void);
#endif #endif
static Sg_device **sg_dev_arr = NULL; static Sg_device **sg_dev_arr = NULL;
static int sg_dev_noticed;
static int sg_dev_max;
static int sg_nr_dev;
#define SZ_SG_HEADER sizeof(struct sg_header) #define SZ_SG_HEADER sizeof(struct sg_header)
#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
...@@ -1340,59 +1341,10 @@ static struct file_operations sg_fops = { ...@@ -1340,59 +1341,10 @@ static struct file_operations sg_fops = {
static int static int
sg_detect(Scsi_Device * scsidp) sg_detect(Scsi_Device * scsidp)
{ {
sg_template.dev_noticed++; sg_dev_noticed++;
return 1; return 1;
} }
/* Driver initialization */
static int
sg_init()
{
static int sg_registered = 0;
unsigned long iflags;
int tmp_dev_max;
Sg_device **tmp_da;
if ((sg_template.dev_noticed == 0) || sg_dev_arr)
return 0;
SCSI_LOG_TIMEOUT(3, printk("sg_init\n"));
write_lock_irqsave(&sg_dev_arr_lock, iflags);
tmp_dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
tmp_da = (Sg_device **)vmalloc(
tmp_dev_max * sizeof(Sg_device *));
if (NULL == tmp_da) {
printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
return 1;
}
write_lock_irqsave(&sg_dev_arr_lock, iflags);
if (!sg_registered) {
if (register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops)) {
printk(KERN_ERR
"Unable to get major %d for generic SCSI device\n",
SCSI_GENERIC_MAJOR);
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
vfree((char *) tmp_da);
return 1;
}
sg_registered++;
}
memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
sg_template.dev_max = tmp_dev_max;
sg_dev_arr = tmp_da;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
#ifdef CONFIG_PROC_FS
sg_proc_init();
#endif /* CONFIG_PROC_FS */
return 0;
}
#ifndef MODULE #ifndef MODULE
static int __init static int __init
sg_def_reserved_size_setup(char *str) sg_def_reserved_size_setup(char *str)
...@@ -1444,36 +1396,37 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1444,36 +1396,37 @@ sg_attach(Scsi_Device * scsidp)
if (!disk) if (!disk)
return 1; return 1;
if (scsi_slave_attach(scsidp))
return 1;
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ if (sg_nr_dev >= sg_dev_max) { /* try to resize */
Sg_device **tmp_da; Sg_device **tmp_da;
int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
tmp_da = (Sg_device **)vmalloc( tmp_da = (Sg_device **)vmalloc(
tmp_dev_max * sizeof(Sg_device *)); tmp_dev_max * sizeof(Sg_device *));
if (NULL == tmp_da) { if (NULL == tmp_da) {
scsidp->attached--;
printk(KERN_ERR printk(KERN_ERR
"sg_attach: device array cannot be resized\n"); "sg_attach: device array cannot be resized\n");
put_disk(disk); put_disk(disk);
scsi_slave_detach(scsidp);
return 1; return 1;
} }
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *)); memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
memcpy(tmp_da, sg_dev_arr, memcpy(tmp_da, sg_dev_arr,
sg_template.dev_max * sizeof (Sg_device *)); sg_dev_max * sizeof (Sg_device *));
vfree((char *) sg_dev_arr); vfree((char *) sg_dev_arr);
sg_dev_arr = tmp_da; sg_dev_arr = tmp_da;
sg_template.dev_max = tmp_dev_max; sg_dev_max = tmp_dev_max;
} }
find_empty_slot: find_empty_slot:
for (k = 0; k < sg_template.dev_max; k++) for (k = 0; k < sg_dev_max; k++)
if (!sg_dev_arr[k]) if (!sg_dev_arr[k])
break; break;
if (k > SG_MAX_DEVS_MASK) { if (k > SG_MAX_DEVS_MASK) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
printk(KERN_WARNING printk(KERN_WARNING
"Unable to attach sg device <%d, %d, %d, %d>" "Unable to attach sg device <%d, %d, %d, %d>"
...@@ -1483,9 +1436,10 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1483,9 +1436,10 @@ sg_attach(Scsi_Device * scsidp)
if (NULL != sdp) if (NULL != sdp)
vfree((char *) sdp); vfree((char *) sdp);
put_disk(disk); put_disk(disk);
scsi_slave_detach(scsidp);
return 1; return 1;
} }
if (k < sg_template.dev_max) { if (k < sg_dev_max) {
if (NULL == sdp) { if (NULL == sdp) {
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
sdp = (Sg_device *)vmalloc(sizeof(Sg_device)); sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
...@@ -1496,10 +1450,10 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1496,10 +1450,10 @@ sg_attach(Scsi_Device * scsidp)
} else } else
sdp = NULL; sdp = NULL;
if (NULL == sdp) { if (NULL == sdp) {
scsidp->attached--;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
put_disk(disk); put_disk(disk);
scsi_slave_detach(scsidp);
return 1; return 1;
} }
...@@ -1527,7 +1481,7 @@ sg_attach(Scsi_Device * scsidp) ...@@ -1527,7 +1481,7 @@ sg_attach(Scsi_Device * scsidp)
sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev; sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type; sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
sg_template.nr_dev++; sg_nr_dev++;
sg_dev_arr[k] = sdp; sg_dev_arr[k] = sdp;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
...@@ -1570,7 +1524,7 @@ sg_detach(Scsi_Device * scsidp) ...@@ -1570,7 +1524,7 @@ sg_detach(Scsi_Device * scsidp)
return; return;
delay = 0; delay = 0;
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
for (k = 0; k < sg_template.dev_max; k++) { for (k = 0; k < sg_dev_max; k++) {
sdp = sg_dev_arr[k]; sdp = sg_dev_arr[k];
if ((NULL == sdp) || (sdp->device != scsidp)) if ((NULL == sdp) || (sdp->device != scsidp))
continue; /* dirty but lowers nesting */ continue; /* dirty but lowers nesting */
...@@ -1607,9 +1561,9 @@ sg_detach(Scsi_Device * scsidp) ...@@ -1607,9 +1561,9 @@ sg_detach(Scsi_Device * scsidp)
SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
sg_dev_arr[k] = NULL; sg_dev_arr[k] = NULL;
} }
scsidp->attached--; scsi_slave_detach(scsidp);
sg_template.nr_dev--; sg_nr_dev--;
sg_template.dev_noticed--; /* from <dan@lectra.fr> */ sg_dev_noticed--; /* from <dan@lectra.fr> */
break; break;
} }
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
...@@ -1643,9 +1597,21 @@ MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); ...@@ -1643,9 +1597,21 @@ MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
static int __init static int __init
init_sg(void) init_sg(void)
{ {
int rc;
if (def_reserved_size >= 0) if (def_reserved_size >= 0)
sg_big_buff = def_reserved_size; sg_big_buff = def_reserved_size;
return scsi_register_device(&sg_template);
rc = register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops);
if (rc)
return rc;
rc = scsi_register_device(&sg_template);
if (rc)
return rc;
#ifdef CONFIG_PROC_FS
sg_proc_init();
#endif /* CONFIG_PROC_FS */
return 0;
} }
static void __exit static void __exit
...@@ -1660,7 +1626,7 @@ exit_sg(void) ...@@ -1660,7 +1626,7 @@ exit_sg(void)
vfree((char *) sg_dev_arr); vfree((char *) sg_dev_arr);
sg_dev_arr = NULL; sg_dev_arr = NULL;
} }
sg_template.dev_max = 0; sg_dev_max = 0;
} }
static int static int
...@@ -2552,7 +2518,7 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) ...@@ -2552,7 +2518,7 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
if (sdp->detached && (NULL == sdp->headfp)) { if (sdp->detached && (NULL == sdp->headfp)) {
int k, maxd; int k, maxd;
maxd = sg_template.dev_max; maxd = sg_dev_max;
for (k = 0; k < maxd; ++k) { for (k = 0; k < maxd; ++k) {
if (sdp == sg_dev_arr[k]) if (sdp == sg_dev_arr[k])
break; break;
...@@ -2684,7 +2650,7 @@ sg_last_dev() ...@@ -2684,7 +2650,7 @@ sg_last_dev()
unsigned long iflags; unsigned long iflags;
read_lock_irqsave(&sg_dev_arr_lock, iflags); read_lock_irqsave(&sg_dev_arr_lock, iflags);
for (k = sg_template.dev_max - 1; k >= 0; --k) for (k = sg_dev_max - 1; k >= 0; --k)
if (sg_dev_arr[k] && sg_dev_arr[k]->device) if (sg_dev_arr[k] && sg_dev_arr[k]->device)
break; break;
read_unlock_irqrestore(&sg_dev_arr_lock, iflags); read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
...@@ -2700,7 +2666,7 @@ sg_get_dev(int dev) ...@@ -2700,7 +2666,7 @@ sg_get_dev(int dev)
if (sg_dev_arr && (dev >= 0)) { if (sg_dev_arr && (dev >= 0)) {
read_lock_irqsave(&sg_dev_arr_lock, iflags); read_lock_irqsave(&sg_dev_arr_lock, iflags);
if (dev < sg_template.dev_max) if (dev < sg_dev_max)
sdp = sg_dev_arr[dev]; sdp = sg_dev_arr[dev];
read_unlock_irqrestore(&sg_dev_arr_lock, iflags); read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
} }
...@@ -2982,7 +2948,7 @@ sg_proc_debug_info(char *buffer, int *len, off_t * begin, ...@@ -2982,7 +2948,7 @@ sg_proc_debug_info(char *buffer, int *len, off_t * begin,
} }
max_dev = sg_last_dev(); max_dev = sg_last_dev();
PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n", PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
sg_template.dev_max, max_dev); sg_dev_max, max_dev);
PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff); PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
for (j = 0; j < max_dev; ++j) { for (j = 0; j < max_dev; ++j) {
if ((sdp = sg_get_dev(j))) { if ((sdp = sg_get_dev(j))) {
......
...@@ -65,11 +65,9 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */ ...@@ -65,11 +65,9 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */
CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \ CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET) CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET)
static int sr_init(void);
static int sr_attach(struct scsi_device *); static int sr_attach(struct scsi_device *);
static int sr_detect(struct scsi_device *); static int sr_detect(struct scsi_device *);
static void sr_detach(struct scsi_device *); static void sr_detach(struct scsi_device *);
static int sr_init_command(struct scsi_cmnd *); static int sr_init_command(struct scsi_cmnd *);
static struct Scsi_Device_Template sr_template = { static struct Scsi_Device_Template sr_template = {
...@@ -77,24 +75,54 @@ static struct Scsi_Device_Template sr_template = { ...@@ -77,24 +75,54 @@ static struct Scsi_Device_Template sr_template = {
.name = "cdrom", .name = "cdrom",
.tag = "sr", .tag = "sr",
.scsi_type = TYPE_ROM, .scsi_type = TYPE_ROM,
.blk = 1,
.detect = sr_detect, .detect = sr_detect,
.init = sr_init,
.attach = sr_attach, .attach = sr_attach,
.detach = sr_detach, .detach = sr_detach,
.init_command = sr_init_command .init_command = sr_init_command
}; };
static struct scsi_cd *scsi_CDs; static int sr_nr_dev; /* XXX(hch) bad hack, we want a bitmap instead */
static LIST_HEAD(sr_devlist);
static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED;
static int sr_open(struct cdrom_device_info *, int); static int sr_open(struct cdrom_device_info *, int);
static void get_sectorsize(struct scsi_cd *); static void get_sectorsize(struct scsi_cd *);
static void get_capabilities(struct scsi_cd *); static void get_capabilities(struct scsi_cd *);
static int sr_init_one(struct scsi_cd *, int);
static int sr_media_change(struct cdrom_device_info *, int); static int sr_media_change(struct cdrom_device_info *, int);
static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
static Scsi_CD *sr_find_by_sdev(Scsi_Device *sd)
{
struct list_head *p;
Scsi_CD *cd;
spin_lock(&sr_devlist_lock);
list_for_each(p, &sr_devlist) {
cd = list_entry(p, Scsi_CD, list);
if (cd->device == sd) {
spin_unlock(&sr_devlist_lock);
return cd;
}
}
spin_unlock(&sr_devlist_lock);
return NULL;
}
static inline void sr_devlist_insert(Scsi_CD *cd)
{
spin_lock(&sr_devlist_lock);
list_add(&cd->list, &sr_devlist);
spin_unlock(&sr_devlist_lock);
}
static inline void sr_devlist_remove(Scsi_CD *cd)
{
spin_lock(&sr_devlist_lock);
list_del(&cd->list);
spin_unlock(&sr_devlist_lock);
}
static void sr_release(struct cdrom_device_info *cdi) static void sr_release(struct cdrom_device_info *cdi)
{ {
struct scsi_cd *cd = cdi->handle; struct scsi_cd *cd = cdi->handle;
...@@ -466,44 +494,90 @@ static int sr_detect(struct scsi_device * SDp) ...@@ -466,44 +494,90 @@ static int sr_detect(struct scsi_device * SDp)
if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
return 0; return 0;
sr_template.dev_noticed++;
return 1; return 1;
} }
static int sr_attach(struct scsi_device * SDp) static int sr_attach(struct scsi_device *sdev)
{ {
struct scsi_cd *cpnt; struct gendisk *disk;
int i; struct scsi_cd *cd;
int minor;
if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
return 1; return 1;
if (sr_template.nr_dev >= sr_template.dev_max) if (scsi_slave_attach(sdev))
return 1;
cd = kmalloc(sizeof(*cd), GFP_KERNEL);
if (!cd)
goto fail; goto fail;
memset(cd, 0, sizeof(*cd));
for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) disk = alloc_disk(1);
if (!cpnt->device) if (!disk)
break; goto fail_free;
if (i >= sr_template.dev_max) /*
panic("scsi_devices corrupt (sr)"); * XXX This doesn't make us better than the previous code in the
* XXX end (not worse either, though..).
* XXX To properly support hotplugging we should have a bitmap and
* XXX use find_first_zero_bit on it. This will happen at the
* XXX same time template->nr_* goes away. --hch
*/
minor = sr_nr_dev++;
scsi_CDs[i].device = SDp; disk->major = MAJOR_NR;
disk->first_minor = minor;
sprintf(disk->disk_name, "sr%d", minor);
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
if (sr_init_one(cpnt, i)) cd->device = sdev;
goto fail; cd->disk = disk;
cd->driver = &sr_template;
cd->disk = disk;
cd->capacity = 0x1fffff;
cd->needs_sector_size = 1;
cd->device->changed = 1; /* force recheck CD type */
cd->use = 1;
cd->readcd_known = 0;
cd->readcd_cdda = 0;
cd->cdi.ops = &sr_dops;
cd->cdi.handle = cd;
cd->cdi.mask = 0;
cd->cdi.capacity = 1;
sprintf(cd->cdi.name, "sr%d", minor);
sr_template.nr_dev++; sdev->sector_size = 2048; /* A guess, just in case */
if (sr_template.nr_dev > sr_template.dev_max) sdev->ten = 1;
panic("scsi_devices corrupt (sr)"); sdev->remap = 1;
/* FIXME: need to handle a get_capabilities failure properly ?? */
get_capabilities(cd);
sr_vendor_init(cd);
printk("Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n", disk->de = sdev->de;
scsi_CDs[i].cdi.name, SDp->host->host_no, SDp->channel, disk->driverfs_dev = &sdev->sdev_driverfs_dev;
SDp->id, SDp->lun); register_cdrom(&cd->cdi);
set_capacity(disk, cd->capacity);
disk->private_data = &cd->driver;
disk->queue = &sdev->request_queue;
add_disk(disk);
sr_devlist_insert(cd);
printk(KERN_DEBUG
"Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
cd->cdi.name, sdev->host->host_no, sdev->channel,
sdev->id, sdev->lun);
return 0; return 0;
fail_free:
kfree(cd);
fail: fail:
SDp->attached--; scsi_slave_detach(sdev);
return 1; return 1;
} }
...@@ -723,126 +797,32 @@ static int sr_packet(struct cdrom_device_info *cdi, ...@@ -723,126 +797,32 @@ static int sr_packet(struct cdrom_device_info *cdi,
return cgc->stat; return cgc->stat;
} }
static int sr_registered; static void sr_detach(struct scsi_device * SDp)
static int sr_init()
{
int i;
if (sr_template.dev_noticed == 0)
return 0;
if (!sr_registered) {
if (register_blkdev(MAJOR_NR, "sr", &sr_bdops)) {
printk("Unable to get major %d for SCSI-CD\n",
MAJOR_NR);
return 1;
}
sr_registered++;
}
if (scsi_CDs)
return 0;
sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
scsi_CDs = kmalloc(sr_template.dev_max * sizeof(struct scsi_cd), GFP_ATOMIC);
if (!scsi_CDs)
goto cleanup_dev;
memset(scsi_CDs, 0, sr_template.dev_max * sizeof(struct scsi_cd));
for (i = 0; i < sr_template.dev_max; i++)
sprintf(scsi_CDs[i].cdi.name, "sr%d", i);
return 0;
cleanup_dev:
unregister_blkdev(MAJOR_NR, "sr");
sr_registered--;
return 1;
}
static int sr_init_one(struct scsi_cd *cd, int first_minor)
{ {
struct gendisk *disk; struct scsi_cd *cd;
disk = alloc_disk(1);
if (!disk)
return -ENOMEM;
disk->major = MAJOR_NR;
disk->first_minor = first_minor;
strcpy(disk->disk_name, cd->cdi.name);
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
cd->driver = &sr_template;
cd->disk = disk;
cd->capacity = 0x1fffff;
cd->device->sector_size = 2048;/* A guess, just in case */
cd->needs_sector_size = 1;
cd->device->changed = 1; /* force recheck CD type */
#if 0
/* seems better to leave this for later */
get_sectorsize(cd);
printk("Scd sectorsize = %d bytes.\n", cd->sector_size);
#endif
cd->use = 1;
cd->device->ten = 1;
cd->device->remap = 1;
cd->readcd_known = 0;
cd->readcd_cdda = 0;
cd->cdi.ops = &sr_dops; cd = sr_find_by_sdev(SDp);
cd->cdi.handle = cd; if (!cd)
cd->cdi.mask = 0; return;
cd->cdi.capacity = 1;
/*
* FIXME: someone needs to handle a get_capabilities
* failure properly ??
*/
get_capabilities(cd);
sr_vendor_init(cd);
disk->de = cd->device->de;
disk->driverfs_dev = &cd->device->sdev_driverfs_dev;
register_cdrom(&cd->cdi);
set_capacity(disk, cd->capacity);
disk->private_data = &cd->driver;
disk->queue = &cd->device->request_queue;
add_disk(disk);
return 0;
}
static void sr_detach(struct scsi_device * SDp) sr_devlist_remove(cd);
{ del_gendisk(cd->disk);
struct scsi_cd *cpnt; put_disk(cd->disk);
int i; unregister_cdrom(&cd->cdi);
for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) { scsi_slave_detach(SDp);
if (cpnt->device == SDp) { sr_nr_dev--;
/*
* Since the cdrom is read-only, no need to sync
* the device.
* We should be kind to our buffer cache, however.
*/
del_gendisk(cpnt->disk);
put_disk(cpnt->disk);
cpnt->disk = NULL;
/* kfree(cd);
* Reset things back to a sane state so that one can
* re-load a new driver (perhaps the same one).
*/
unregister_cdrom(&(cpnt->cdi));
cpnt->device = NULL;
cpnt->capacity = 0;
SDp->attached--;
sr_template.nr_dev--;
sr_template.dev_noticed--;
return;
}
}
} }
static int __init init_sr(void) static int __init init_sr(void)
{ {
int rc;
rc = register_blkdev(MAJOR_NR, "sr", &sr_bdops);
if (rc)
return rc;
return scsi_register_device(&sr_template); return scsi_register_device(&sr_template);
} }
...@@ -850,11 +830,6 @@ static void __exit exit_sr(void) ...@@ -850,11 +830,6 @@ static void __exit exit_sr(void)
{ {
scsi_unregister_device(&sr_template); scsi_unregister_device(&sr_template);
unregister_blkdev(MAJOR_NR, "sr"); unregister_blkdev(MAJOR_NR, "sr");
sr_registered--;
if (scsi_CDs != NULL)
kfree(scsi_CDs);
sr_template.dev_max = 0;
} }
module_init(init_sr); module_init(init_sr);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
typedef struct scsi_cd { typedef struct scsi_cd {
struct Scsi_Device_Template *driver; struct Scsi_Device_Template *driver;
struct list_head list;
unsigned capacity; /* size in blocks */ unsigned capacity; /* size in blocks */
Scsi_Device *device; Scsi_Device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned int vendor; /* vendor code, see sr_vendor.c */
......
...@@ -74,6 +74,9 @@ static int try_direct_io = TRY_DIRECT_IO; ...@@ -74,6 +74,9 @@ static int try_direct_io = TRY_DIRECT_IO;
static int try_rdio = TRUE; static int try_rdio = TRUE;
static int try_wdio = TRUE; static int try_wdio = TRUE;
static int st_dev_max;
static int st_nr_dev;
MODULE_AUTHOR("Kai Makisara"); MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver"); MODULE_DESCRIPTION("SCSI Tape Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -976,7 +979,7 @@ static int st_open(struct inode *inode, struct file *filp) ...@@ -976,7 +979,7 @@ static int st_open(struct inode *inode, struct file *filp)
char *name; char *name;
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
if (dev >= st_template.dev_max || scsi_tapes == NULL || if (dev >= st_dev_max || scsi_tapes == NULL ||
((STp = scsi_tapes[dev]) == NULL)) { ((STp = scsi_tapes[dev]) == NULL)) {
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
return (-ENXIO); return (-ENXIO);
...@@ -3664,6 +3667,9 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3664,6 +3667,9 @@ static int st_attach(Scsi_Device * SDp)
return 1; return 1;
} }
if (scsi_slave_attach(SDp))
return 1;
i = SDp->host->sg_tablesize; i = SDp->host->sg_tablesize;
if (st_max_sg_segs < i) if (st_max_sg_segs < i)
i = st_max_sg_segs; i = st_max_sg_segs;
...@@ -3680,20 +3686,20 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3680,20 +3686,20 @@ static int st_attach(Scsi_Device * SDp)
} }
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
if (st_template.nr_dev >= st_template.dev_max) { if (st_nr_dev >= st_dev_max) {
Scsi_Tape **tmp_da; Scsi_Tape **tmp_da;
ST_buffer **tmp_ba; ST_buffer **tmp_ba;
int tmp_dev_max; int tmp_dev_max;
tmp_dev_max = st_template.nr_dev + ST_DEV_ARR_LUMP; tmp_dev_max = st_nr_dev + ST_DEV_ARR_LUMP;
if (tmp_dev_max > ST_MAX_TAPES) if (tmp_dev_max > ST_MAX_TAPES)
tmp_dev_max = ST_MAX_TAPES; tmp_dev_max = ST_MAX_TAPES;
if (tmp_dev_max <= st_template.nr_dev) { if (tmp_dev_max <= st_nr_dev) {
SDp->attached--;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Too many tape devices (max. %d).\n", printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
ST_MAX_TAPES); ST_MAX_TAPES);
put_disk(disk); put_disk(disk);
scsi_slave_detach(SDp);
return 1; return 1;
} }
...@@ -3704,36 +3710,36 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3704,36 +3710,36 @@ static int st_attach(Scsi_Device * SDp)
kfree(tmp_da); kfree(tmp_da);
if (tmp_ba != NULL) if (tmp_ba != NULL)
kfree(tmp_ba); kfree(tmp_ba);
SDp->attached--;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't extend device array.\n"); printk(KERN_ERR "st: Can't extend device array.\n");
put_disk(disk); put_disk(disk);
scsi_slave_detach(SDp);
return 1; return 1;
} }
memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *)); memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *));
if (scsi_tapes != NULL) { if (scsi_tapes != NULL) {
memcpy(tmp_da, scsi_tapes, memcpy(tmp_da, scsi_tapes,
st_template.dev_max * sizeof(Scsi_Tape *)); st_dev_max * sizeof(Scsi_Tape *));
kfree(scsi_tapes); kfree(scsi_tapes);
} }
scsi_tapes = tmp_da; scsi_tapes = tmp_da;
st_template.dev_max = tmp_dev_max; st_dev_max = tmp_dev_max;
} }
for (i = 0; i < st_template.dev_max; i++) for (i = 0; i < st_dev_max; i++)
if (scsi_tapes[i] == NULL) if (scsi_tapes[i] == NULL)
break; break;
if (i >= st_template.dev_max) if (i >= st_dev_max)
panic("scsi_devices corrupt (st)"); panic("scsi_devices corrupt (st)");
tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC); tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
if (tpnt == NULL) { if (tpnt == NULL) {
SDp->attached--;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
printk(KERN_ERR "st: Can't allocate device descriptor.\n"); printk(KERN_ERR "st: Can't allocate device descriptor.\n");
put_disk(disk); put_disk(disk);
scsi_slave_detach(SDp);
return 1; return 1;
} }
memset(tpnt, 0, sizeof(Scsi_Tape)); memset(tpnt, 0, sizeof(Scsi_Tape));
...@@ -3821,7 +3827,7 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3821,7 +3827,7 @@ static int st_attach(Scsi_Device * SDp)
tpnt->blksize_changed = FALSE; tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock); init_MUTEX(&tpnt->lock);
st_template.nr_dev++; st_nr_dev++;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
...@@ -3883,7 +3889,6 @@ static int st_detect(Scsi_Device * SDp) ...@@ -3883,7 +3889,6 @@ static int st_detect(Scsi_Device * SDp)
{ {
if (SDp->type != TYPE_TAPE || st_incompatible(SDp)) if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
return 0; return 0;
st_template.dev_noticed++;
return 1; return 1;
} }
...@@ -3893,7 +3898,7 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3893,7 +3898,7 @@ static void st_detach(Scsi_Device * SDp)
int i, mode; int i, mode;
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
for (i = 0; i < st_template.dev_max; i++) { for (i = 0; i < st_dev_max; i++) {
tpnt = scsi_tapes[i]; tpnt = scsi_tapes[i];
if (tpnt != NULL && tpnt->device == SDp) { if (tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL; tpnt->device = NULL;
...@@ -3904,9 +3909,8 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3904,9 +3909,8 @@ static void st_detach(Scsi_Device * SDp)
tpnt->de_n[mode] = NULL; tpnt->de_n[mode] = NULL;
} }
scsi_tapes[i] = 0; scsi_tapes[i] = 0;
SDp->attached--; scsi_slave_detach(SDp);
st_template.nr_dev--; st_nr_dev--;
st_template.dev_noticed--;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
...@@ -3962,14 +3966,13 @@ static void __exit exit_st(void) ...@@ -3962,14 +3966,13 @@ static void __exit exit_st(void)
scsi_unregister_device(&st_template); scsi_unregister_device(&st_template);
unregister_chrdev(SCSI_TAPE_MAJOR, "st"); unregister_chrdev(SCSI_TAPE_MAJOR, "st");
if (scsi_tapes != NULL) { if (scsi_tapes != NULL) {
for (i=0; i < st_template.dev_max; ++i) for (i=0; i < st_dev_max; ++i)
if (scsi_tapes[i]) { if (scsi_tapes[i]) {
put_disk(scsi_tapes[i]->disk); put_disk(scsi_tapes[i]->disk);
kfree(scsi_tapes[i]); kfree(scsi_tapes[i]);
} }
kfree(scsi_tapes); kfree(scsi_tapes);
} }
st_template.dev_max = 0;
printk(KERN_INFO "st: Unloaded.\n"); printk(KERN_INFO "st: Unloaded.\n");
} }
......
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