Commit 1ad65843 authored by Christoph Hellwig's avatar Christoph Hellwig

[PATCH] some scsi_scan.c restructuring for ieee1394 hotplugging

I had some discussion with Ben Collins on ow to properly allow
hotplugging of ieee1394 storage device (sbp2).  While the scsi_add_host/
scsi_remove_host interface allows hotpluging of ieee1394 adapters we
need a way to register the actual devices with the scsi layer when
they're plugged in.  I've restructured the code to handle the
/proc/scsi/scsi code to add/remove devices a bit to have an interface
the ieee1394 driver can use, and created the following new interface:

	struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
			uint channel, uint id, uint lun)
	int scsi_remove_device(struct scsi_device *sdev)

in addition scsi_probe_and_add_lun() got some overhaul to become
readable and can now return the struct scsi_device it probed as an
optional argument.
parent 611f4c04
...@@ -270,21 +270,6 @@ int scsi_remove_host(struct Scsi_Host *shost) ...@@ -270,21 +270,6 @@ int scsi_remove_host(struct Scsi_Host *shost)
if (scsi_check_device_busy(sdev)) if (scsi_check_device_busy(sdev))
return 1; return 1;
/*
* Next we detach the high level drivers from the Scsi_Device
* structures
*/
list_for_each_entry(sdev, &shost->my_devices, siblings) {
scsi_detach_device(sdev);
/* If something still attached, punt */
if (sdev->attached) {
printk(KERN_ERR "Attached usage count = %d\n",
sdev->attached);
return 1;
}
}
scsi_forget_host(shost); scsi_forget_host(shost);
return 0; return 0;
} }
......
...@@ -503,8 +503,9 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *); ...@@ -503,8 +503,9 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *);
/* /*
* Prototypes for functions in scsi_scan.c * Prototypes for functions in scsi_scan.c
*/ */
extern int scsi_add_single_device(uint, uint, uint, uint); extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
extern int scsi_remove_single_device(uint, uint, uint, uint); uint, uint, uint);
extern int scsi_remove_device(struct scsi_device *);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
/* /*
......
...@@ -398,6 +398,50 @@ static void scsi_dump_status(int level) ...@@ -398,6 +398,50 @@ static void scsi_dump_status(int level)
} }
#endif /* CONFIG_SCSI_LOGGING */ #endif /* CONFIG_SCSI_LOGGING */
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
if (!scsi_find_device(shost, channel, id, lun)) {
sdev = scsi_add_device(shost, channel, id, lun);
if (IS_ERR(sdev))
error = PTR_ERR(sdev);
else
error = 0;
}
scsi_host_put(shost);
return error;
}
static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
sdev = scsi_find_device(shost, channel, id, lun);
if (!sdev)
goto out;
if (sdev->access_count)
goto out;
error = scsi_remove_device(sdev);
out:
scsi_host_put(shost);
return error;
}
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)
{ {
......
...@@ -1313,14 +1313,6 @@ static int scsi_add_lun(Scsi_Device *sdev, Scsi_Request *sreq, ...@@ -1313,14 +1313,6 @@ static int scsi_add_lun(Scsi_Device *sdev, Scsi_Request *sreq,
return SCSI_SCAN_LUN_PRESENT; return SCSI_SCAN_LUN_PRESENT;
} }
static void scsi_remove_lun(struct scsi_device *sdev)
{
devfs_unregister(sdev->de);
scsi_device_unregister(sdev);
scsi_free_sdev(sdev);
}
/** /**
* scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
* @sdevscan: probe the LUN corresponding to this Scsi_Device * @sdevscan: probe the LUN corresponding to this Scsi_Device
...@@ -1338,90 +1330,77 @@ static void scsi_remove_lun(struct scsi_device *sdev) ...@@ -1338,90 +1330,77 @@ static void scsi_remove_lun(struct scsi_device *sdev)
* SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
**/ **/
static int scsi_probe_and_add_lun(struct Scsi_Host *host, static int scsi_probe_and_add_lun(struct Scsi_Host *host,
struct request_queue **q, uint channel, uint id, struct request_queue **q, uint channel, uint id, uint lun,
uint lun, int *bflagsp) int *bflagsp, struct scsi_device **sdevp)
{ {
Scsi_Device *sdev = NULL; struct scsi_device *sdev;
Scsi_Request *sreq = NULL; struct scsi_request *sreq;
unsigned char *scsi_result = NULL; unsigned char *result;
int bflags; int bflags, res = SCSI_SCAN_NO_RESPONSE;
int res;
sdev = scsi_alloc_sdev(host, q, channel, id, lun); sdev = scsi_alloc_sdev(host, q, channel, id, lun);
if (sdev == NULL) if (!sdev)
return SCSI_SCAN_NO_RESPONSE; goto out;
sreq = scsi_allocate_request(sdev); sreq = scsi_allocate_request(sdev);
if (sreq == NULL) { if (!sreq)
printk(ALLOC_FAILURE_MSG, __FUNCTION__); goto out_free_sdev;
res = SCSI_SCAN_NO_RESPONSE; result = kmalloc(256, GFP_ATOMIC |
goto bail_out; (host->unchecked_isa_dma) ? __GFP_DMA : 0);
} if (!result)
goto out_free_sreq;
scsi_probe_lun(sreq, result, &bflags);
if (sreq->sr_result)
goto out_free_result;
/* /*
* The sreq is for use only with sdevscan. * result contains valid SCSI INQUIRY data.
*/ */
if ((result[0] >> 5) == 3) {
scsi_result = kmalloc(256, GFP_ATOMIC |
(host->unchecked_isa_dma) ?
GFP_DMA : 0);
if (scsi_result == NULL) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
res = SCSI_SCAN_NO_RESPONSE;
goto bail_out;
}
scsi_probe_lun(sreq, scsi_result, &bflags);
if (sreq->sr_result)
res = SCSI_SCAN_NO_RESPONSE;
else {
/* /*
* scsi_result contains valid SCSI INQUIRY data. * For a Peripheral qualifier 3 (011b), the SCSI
* spec says: The device server is not capable of
* supporting a physical device on this logical
* unit.
*
* For disks, this implies that there is no
* logical disk configured at sdev->lun, but there
* is a target id responding.
*/ */
if ((scsi_result[0] >> 5) == 3) { SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
/*
* For a Peripheral qualifier 3 (011b), the SCSI
* spec says: The device server is not capable of
* supporting a physical device on this logical
* unit.
*
* For disks, this implies that there is no
* logical disk configured at sdev->lun, but there
* is a target id responding.
*/
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: peripheral qualifier of 3," "scsi scan: peripheral qualifier of 3,"
" no device added\n")); " no device added\n"));
res = SCSI_SCAN_TARGET_PRESENT; res = SCSI_SCAN_TARGET_PRESENT;
} else { goto out_free_result;
res = scsi_add_lun(sdev, sreq, scsi_result, &bflags); }
if (res == SCSI_SCAN_LUN_PRESENT) {
if ((bflags & BLIST_KEY) != 0) { res = scsi_add_lun(sdev, sreq, result, &bflags);
sdev->lockable = 0; if (res == SCSI_SCAN_LUN_PRESENT) {
scsi_unlock_floptical(sreq, if (bflags & BLIST_KEY) {
scsi_result); sdev->lockable = 0;
/* scsi_unlock_floptical(sreq, result);
* scsi_result no longer contains
* the INQUIRY data.
*/
}
if (bflagsp != NULL)
*bflagsp = bflags;
}
} }
if (bflagsp)
*bflagsp = bflags;
} }
bail_out:
if (scsi_result != NULL) out_free_result:
kfree(scsi_result); kfree(result);
if (sreq != NULL) out_free_sreq:
scsi_release_request(sreq); scsi_release_request(sreq);
if (res != SCSI_SCAN_LUN_PRESENT) { out_free_sdev:
if(q) { if (res == SCSI_SCAN_LUN_PRESENT) {
if (*sdevp)
*sdevp = sdev;
} else {
if (q) {
*q = sdev->request_queue; *q = sdev->request_queue;
sdev->request_queue = NULL; sdev->request_queue = NULL;
} }
scsi_free_sdev(sdev); scsi_free_sdev(sdev);
} }
out:
return res; return res;
} }
/** /**
...@@ -1507,8 +1486,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, ...@@ -1507,8 +1486,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost,
* sparse_lun. * sparse_lun.
*/ */
for (lun = 1; lun < max_dev_lun; ++lun) for (lun = 1; lun < max_dev_lun; ++lun)
if ((scsi_probe_and_add_lun(shost, q, channel, id, lun, NULL) if ((scsi_probe_and_add_lun(shost, q, channel, id, lun,
!= SCSI_SCAN_LUN_PRESENT) && !sparse_lun) NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
return; return;
} }
...@@ -1723,7 +1702,7 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q, ...@@ -1723,7 +1702,7 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q,
int res; int res;
res = scsi_probe_and_add_lun(sdev->host, q, res = scsi_probe_and_add_lun(sdev->host, q,
sdev->channel, sdev->id, lun, NULL); sdev->channel, sdev->id, lun, NULL, NULL);
if (res == SCSI_SCAN_NO_RESPONSE) { if (res == SCSI_SCAN_NO_RESPONSE) {
/* /*
* Got some results, but now none, abort. * Got some results, but now none, abort.
...@@ -1745,55 +1724,33 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q, ...@@ -1745,55 +1724,33 @@ static int scsi_report_lun_scan(Scsi_Device *sdev, struct request_queue **q,
} }
int scsi_add_single_device(uint host, uint channel, uint id, uint lun) struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
uint channel, uint id, uint lun)
{ {
struct Scsi_Host *shost;
int error = -ENODEV;
struct scsi_device *sdev; struct scsi_device *sdev;
int error = -ENODEV, res;
shost = scsi_host_hn_get(host); res = scsi_probe_and_add_lun(shost, NULL, channel, id, lun,
if (!shost) NULL, &sdev);
return -ENODEV; if (res == SCSI_SCAN_LUN_PRESENT)
if(scsi_find_device(shost, channel, id, lun) != NULL) error = scsi_attach_device(sdev);
goto out;
if (scsi_probe_and_add_lun(shost, NULL, channel, id, lun, NULL) == if (error)
SCSI_SCAN_LUN_PRESENT) { sdev = ERR_PTR(error);
error = 0; return sdev;
sdev = scsi_find_device(shost, channel, id, lun);
scsi_attach_device(sdev);
}
out:
scsi_host_put(shost);
return error;
} }
int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) int scsi_remove_device(struct scsi_device *sdev)
{ {
struct scsi_device *sdev;
struct Scsi_Host *shost;
int error = -ENODEV;
shost = scsi_host_hn_get(host);
if (!shost)
return -ENODEV;
sdev = scsi_find_device(shost, channel, id, lun);
if (!sdev)
goto out;
error = -EBUSY;
if (sdev->access_count)
goto out;
scsi_detach_device(sdev); scsi_detach_device(sdev);
if (sdev->attached) if (sdev->attached)
goto out; return -EINVAL;
scsi_remove_lun(sdev); devfs_unregister(sdev->de);
error = 0; scsi_device_unregister(sdev);
out: scsi_free_sdev(sdev);
scsi_host_put(shost); return 0;
return error;
} }
/** /**
...@@ -1832,9 +1789,8 @@ static void scsi_scan_target(struct Scsi_Host *shost, struct request_queue **q, ...@@ -1832,9 +1789,8 @@ static void scsi_scan_target(struct Scsi_Host *shost, struct request_queue **q,
* Scan LUN 0, if there is some response, scan further. Ideally, we * Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned. * would not configure LUN 0 until all LUNs are scanned.
*/ */
res = scsi_probe_and_add_lun(shost, q, channel, id, 0, &bflags); res = scsi_probe_and_add_lun(shost, q, channel, id, 0, &bflags, &sdev);
if (res == SCSI_SCAN_LUN_PRESENT) { if (res == SCSI_SCAN_LUN_PRESENT) {
sdev = scsi_find_device(shost, channel, id, 0);
if (scsi_report_lun_scan(sdev, q, bflags) != 0) if (scsi_report_lun_scan(sdev, q, bflags) != 0)
/* /*
* The REPORT LUN did not scan the target, * The REPORT LUN did not scan the target,
...@@ -1900,9 +1856,13 @@ void scsi_scan_host(struct Scsi_Host *shost) ...@@ -1900,9 +1856,13 @@ void scsi_scan_host(struct Scsi_Host *shost)
void scsi_forget_host(struct Scsi_Host *shost) void scsi_forget_host(struct Scsi_Host *shost)
{ {
struct list_head *le, *lh; struct list_head *le, *lh;
struct scsi_device *sdev;
list_for_each_safe(le, lh, &shost->my_devices) list_for_each_safe(le, lh, &shost->my_devices) {
scsi_remove_lun(list_entry(le, struct scsi_device, siblings)); sdev = list_entry(le, struct scsi_device, siblings);
scsi_remove_device(sdev);
}
} }
/* /*
......
...@@ -80,6 +80,8 @@ EXPORT_SYMBOL(scsi_slave_attach); ...@@ -80,6 +80,8 @@ EXPORT_SYMBOL(scsi_slave_attach);
EXPORT_SYMBOL(scsi_slave_detach); EXPORT_SYMBOL(scsi_slave_detach);
EXPORT_SYMBOL(scsi_device_get); EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put); EXPORT_SYMBOL(scsi_device_put);
EXPORT_SYMBOL(scsi_add_device);
EXPORT_SYMBOL(scsi_remove_device);
/* /*
* This symbol is for the highlevel drivers (e.g. sg) only. * This symbol is for the highlevel drivers (e.g. sg) only.
......
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