Commit 4af8adfb authored by Doug Ledford's avatar Doug Ledford

Merge ssh://linux-scsi.bkbits.net/scsi-misc-2.5

into flossy.devel.redhat.com:/usr/local/home/dledford/bk/linus-2.5
parents 71267d9b 4794bf02
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
...@@ -16,26 +16,20 @@ ...@@ -16,26 +16,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
* *
*/ */
#include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/config.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/blk.h> #include <linux/blkdev.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <asm/uaccess.h>
#include "../scsi/scsi.h"
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h> #include <scsi/scsi_ioctl.h>
#include <asm/uaccess.h>
/* Command group 3 is reserved and should never be used. */ /* Command group 3 is reserved and should never be used. */
const unsigned char scsi_command_size[8] = const unsigned char scsi_command_size[8] =
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
#include "NCR53c406a.h"
/* ============================================================= */ /* ============================================================= */
......
...@@ -1601,7 +1601,7 @@ return -ENOTSUPP; ...@@ -1601,7 +1601,7 @@ return -ENOTSUPP;
scsi_cdb[0] = RELEASE; scsi_cdb[0] = RELEASE;
// allocate with wait = true, interruptible = false // allocate with wait = true, interruptible = false
SCpnt = scsi_allocate_device(ScsiDev, 1, 0); SCpnt = scsi_allocate_device(ScsiDev, 1);
{ {
CPQFC_DECLARE_COMPLETION(wait); CPQFC_DECLARE_COMPLETION(wait);
......
...@@ -4599,7 +4599,7 @@ static void gdth_flush(int hanum) ...@@ -4599,7 +4599,7 @@ static void gdth_flush(int hanum)
#if LINUX_VERSION_CODE >= 0x020322 #if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
scp = scsi_allocate_device(sdev, 1, FALSE); scp = scsi_allocate_device(sdev, 1);
scp->cmd_len = 12; scp->cmd_len = 12;
scp->use_sg = 0; scp->use_sg = 0;
#else #else
...@@ -4673,7 +4673,7 @@ void gdth_halt(void) ...@@ -4673,7 +4673,7 @@ void gdth_halt(void)
memset(cmnd, 0xff, MAX_COMMAND_SIZE); memset(cmnd, 0xff, MAX_COMMAND_SIZE);
#if LINUX_VERSION_CODE >= 0x020322 #if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]); sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
scp = scsi_allocate_device(sdev, 1, FALSE); scp = scsi_allocate_device(sdev, 1);
scp->cmd_len = 12; scp->cmd_len = 12;
scp->use_sg = 0; scp->use_sg = 0;
#else #else
......
...@@ -48,7 +48,7 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) ...@@ -48,7 +48,7 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
#if LINUX_VERSION_CODE >= 0x020322 #if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
scp = scsi_allocate_device(sdev, 1, FALSE); scp = scsi_allocate_device(sdev, 1);
if (!scp) if (!scp)
return -ENOMEM; return -ENOMEM;
scp->cmd_len = 12; scp->cmd_len = 12;
...@@ -712,7 +712,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset, ...@@ -712,7 +712,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
#if LINUX_VERSION_CODE >= 0x020322 #if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
scp = scsi_allocate_device(sdev, 1, FALSE); scp = scsi_allocate_device(sdev, 1);
if (!scp) if (!scp)
return -ENOMEM; return -ENOMEM;
scp->cmd_len = 12; scp->cmd_len = 12;
......
...@@ -208,6 +208,48 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost) ...@@ -208,6 +208,48 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost)
return 0; return 0;
} }
static int scsi_check_device_busy(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
struct scsi_cmnd *scmd;
/*
* Loop over all of the commands associated with the
* device. If any of them are busy, then set the state
* back to inactive and bail.
*/
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
if (scmd->request && scmd->request->rq_status != RQ_INACTIVE)
goto active;
/*
* No, this device is really free. Mark it as such, and
* continue on.
*/
scmd->state = SCSI_STATE_DISCONNECTING;
if (scmd->request)
scmd->request->rq_status = RQ_SCSI_DISCONNECTING;
}
return 0;
active:
printk(KERN_ERR "SCSI device not inactive - rq_status=%d, target=%d, "
"pid=%ld, state=%d, owner=%d.\n",
scmd->request->rq_status, scmd->target,
scmd->pid, scmd->state, scmd->owner);
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
if (scmd->request->rq_status == RQ_SCSI_DISCONNECTING)
scmd->request->rq_status = RQ_INACTIVE;
}
}
printk(KERN_ERR "Device busy???\n");
return 1;
}
/** /**
* scsi_remove_host - 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
...@@ -218,7 +260,6 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost) ...@@ -218,7 +260,6 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost)
int scsi_remove_host(struct Scsi_Host *shost) int scsi_remove_host(struct Scsi_Host *shost)
{ {
struct scsi_device *sdev; struct scsi_device *sdev;
struct scsi_cmnd *scmd;
/* /*
* FIXME Do ref counting. We force all of the devices offline to * FIXME Do ref counting. We force all of the devices offline to
...@@ -228,43 +269,9 @@ int scsi_remove_host(struct Scsi_Host *shost) ...@@ -228,43 +269,9 @@ int scsi_remove_host(struct Scsi_Host *shost)
for (sdev = shost->host_queue; sdev; sdev = sdev->next) for (sdev = shost->host_queue; sdev; sdev = sdev->next)
sdev->online = FALSE; sdev->online = FALSE;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) { for (sdev = shost->host_queue; sdev; sdev = sdev->next)
/* if (scsi_check_device_busy(sdev))
* Loop over all of the commands associated with the
* device. If any of them are busy, then set the state
* back to inactive and bail.
*/
for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
if (scmd->request && scmd->request->rq_status !=
RQ_INACTIVE) {
printk(KERN_ERR "SCSI device not inactive"
"- rq_status=%d, target=%d, pid=%ld,"
"state=%d, owner=%d.\n",
scmd->request->rq_status,
scmd->target, scmd->pid,
scmd->state, scmd->owner);
for (sdev = shost->host_queue; sdev;
sdev = sdev->next) {
for (scmd = sdev->device_queue; scmd;
scmd = scmd->next)
if (scmd->request->rq_status ==
RQ_SCSI_DISCONNECTING)
scmd->request->rq_status = RQ_INACTIVE;
}
printk(KERN_ERR "Device busy???\n");
return 1; return 1;
}
/*
* No, this device is really free. Mark it as such, and
* continue on.
*/
scmd->state = SCSI_STATE_DISCONNECTING;
if (scmd->request)
scmd->request->rq_status =
RQ_SCSI_DISCONNECTING; /* Mark as
busy */
}
}
/* /*
* Next we detach the high level drivers from the Scsi_Device * Next we detach the high level drivers from the Scsi_Device
...@@ -308,7 +315,7 @@ int scsi_add_host(struct Scsi_Host *shost) ...@@ -308,7 +315,7 @@ int scsi_add_host(struct Scsi_Host *shost)
sht->info ? sht->info(shost) : sht->name); sht->info ? sht->info(shost) : sht->name);
device_register(&shost->host_driverfs_dev); device_register(&shost->host_driverfs_dev);
scan_scsis(shost, 0, 0, 0, 0); scsi_scan_host(shost);
for (sdev = shost->host_queue; sdev; sdev = sdev->next) { for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
if (sdev->host->hostt != sht) if (sdev->host->hostt != sht)
......
...@@ -519,7 +519,7 @@ static inline void scsi_set_pci_device(struct Scsi_Host *shost, ...@@ -519,7 +519,7 @@ static inline void scsi_set_pci_device(struct Scsi_Host *shost,
/* /*
* Prototypes for functions/data in scsi_scan.c * Prototypes for functions/data in scsi_scan.c
*/ */
extern void scan_scsis(struct Scsi_Host *, uint, uint, uint, uint); extern void scsi_scan_host(struct Scsi_Host *);
struct Scsi_Device_Template struct Scsi_Device_Template
{ {
......
...@@ -974,13 +974,11 @@ static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, ...@@ -974,13 +974,11 @@ static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb,
mega_ioctl_mbox * mbox); mega_ioctl_mbox * mbox);
#endif #endif
static int megadev_open (struct inode *, struct file *);
static int megadev_ioctl_entry (struct inode *, struct file *, static int megadev_ioctl_entry (struct inode *, struct file *,
unsigned int, unsigned long); unsigned int, unsigned long);
static int megadev_ioctl (struct inode *, struct file *, static int megadev_ioctl (struct inode *, struct file *,
unsigned int, unsigned long); unsigned int, unsigned long);
static mega_scb *megadev_doioctl (mega_host_config *, Scsi_Cmnd *); static mega_scb *megadev_doioctl (mega_host_config *, Scsi_Cmnd *);
static int megadev_close (struct inode *, struct file *);
static void megadev_ioctl_done (Scsi_Cmnd *); static void megadev_ioctl_done (Scsi_Cmnd *);
static int mega_init_scb (mega_host_config *); static int mega_init_scb (mega_host_config *);
static void enq_scb_freelist (mega_host_config *, mega_scb *, static void enq_scb_freelist (mega_host_config *, mega_scb *,
......
...@@ -346,6 +346,41 @@ void scsi_release_request(Scsi_Request * req) ...@@ -346,6 +346,41 @@ void scsi_release_request(Scsi_Request * req)
kfree(req); kfree(req);
} }
/*
* FIXME(eric) - this is not at all optimal. Given that
* single lun devices are rare and usually slow
* (i.e. CD changers), this is good enough for now, but
* we may want to come back and optimize this later.
*
* Scan through all of the devices attached to this
* host, and see if any are active or not. If so,
* we need to defer this command.
*
* We really need a busy counter per device. This would
* allow us to more easily figure out whether we should
* do anything here or not.
*/
static int check_all_luns(struct Scsi_Host *shost, struct scsi_device *myself)
{
struct scsi_device *sdev;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
/*
* Only look for other devices on the same bus
* with the same target ID.
*/
if (sdev->channel != myself->channel || sdev->id != myself->id)
continue;
if (sdev == myself)
continue;
if (atomic_read(&sdev->device_active))
return 1;
}
return 0;
}
/* /*
* Function: scsi_allocate_device * Function: scsi_allocate_device
* *
...@@ -372,89 +407,30 @@ void scsi_release_request(Scsi_Request * req) ...@@ -372,89 +407,30 @@ void scsi_release_request(Scsi_Request * req)
* This function is deprecated, and drivers should be * This function is deprecated, and drivers should be
* rewritten to use Scsi_Request instead of Scsi_Cmnd. * rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/ */
struct scsi_cmnd *scsi_allocate_device(struct scsi_device *sdev, int wait)
Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
int interruptable)
{ {
struct Scsi_Host *host; DECLARE_WAITQUEUE(wq, current);
Scsi_Cmnd *SCpnt = NULL; struct Scsi_Host *shost = sdev->host;
Scsi_Device *SDpnt; struct scsi_cmnd *scmnd;
unsigned long flags; unsigned long flags;
if (!device)
panic("No device passed to scsi_allocate_device().\n");
host = device->host;
spin_lock_irqsave(&device_request_lock, flags); spin_lock_irqsave(&device_request_lock, flags);
while (1) {
while (1 == 1) { if (sdev->device_blocked)
SCpnt = NULL;
if (!device->device_blocked) {
if (device->single_lun) {
/*
* FIXME(eric) - this is not at all optimal. Given that
* single lun devices are rare and usually slow
* (i.e. CD changers), this is good enough for now, but
* we may want to come back and optimize this later.
*
* Scan through all of the devices attached to this
* host, and see if any are active or not. If so,
* we need to defer this command.
*
* We really need a busy counter per device. This would
* allow us to more easily figure out whether we should
* do anything here or not.
*/
for (SDpnt = host->host_queue;
SDpnt;
SDpnt = SDpnt->next) {
/*
* Only look for other devices on the same bus
* with the same target ID.
*/
if (SDpnt->channel != device->channel
|| SDpnt->id != device->id
|| SDpnt == device) {
continue;
}
if( atomic_read(&SDpnt->device_active) != 0)
{
break;
}
}
if (SDpnt) {
/*
* Some other device in this cluster is busy.
* If asked to wait, we need to wait, otherwise
* return NULL.
*/
SCpnt = NULL;
goto busy; goto busy;
} if (sdev->single_lun && check_all_luns(shost, sdev))
} goto busy;
/* /*
* Now we can check for a free command block for this device. * Now we can check for a free command block for this device.
*/ */
for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) { for (scmnd = sdev->device_queue; scmnd; scmnd = scmnd->next)
if (SCpnt->request == NULL) if (!scmnd->request)
break; goto found;
}
} busy:
/* if (!wait)
* If we couldn't find a free command block, and we have been goto fail;
* asked to wait, then do so.
*/
if (SCpnt) {
break;
}
busy:
/*
* If we have been asked to wait for a free block, then
* wait here.
*/
if (wait) {
DECLARE_WAITQUEUE(wait, current);
/* /*
* We need to wait for a free commandblock. We need to * We need to wait for a free commandblock. We need to
...@@ -464,80 +440,54 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, ...@@ -464,80 +440,54 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
* to schedule() wouldn't block (well, it might switch, * to schedule() wouldn't block (well, it might switch,
* but the current task will still be schedulable. * but the current task will still be schedulable.
*/ */
add_wait_queue(&device->scpnt_wait, &wait); add_wait_queue(&sdev->scpnt_wait, &wq);
if( interruptable ) {
set_current_state(TASK_INTERRUPTIBLE);
} else {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
}
spin_unlock_irqrestore(&device_request_lock, flags); spin_unlock_irqrestore(&device_request_lock, flags);
/*
* This should block until a device command block
* becomes available.
*/
schedule(); schedule();
spin_lock_irqsave(&device_request_lock, flags); spin_lock_irqsave(&device_request_lock, flags);
remove_wait_queue(&device->scpnt_wait, &wait); remove_wait_queue(&sdev->scpnt_wait, &wq);
/*
* FIXME - Isn't this redundant?? Someone
* else will have forced the state back to running.
*/
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
/*
* In the event that a signal has arrived that we need
* to consider, then simply return NULL. Everyone
* that calls us should be prepared for this
* possibility, and pass the appropriate code back
* to the user.
*/
if( interruptable ) {
if (signal_pending(current)) {
spin_unlock_irqrestore(&device_request_lock, flags);
return NULL;
}
}
} else {
spin_unlock_irqrestore(&device_request_lock, flags);
return NULL;
}
} }
SCpnt->request = NULL; found:
atomic_inc(&SCpnt->host->host_active); scmnd->request = NULL;
atomic_inc(&SCpnt->device->device_active); atomic_inc(&scmnd->host->host_active);
atomic_inc(&scmnd->device->device_active);
SCpnt->buffer = NULL; scmnd->buffer = NULL;
SCpnt->bufflen = 0; scmnd->bufflen = 0;
SCpnt->request_buffer = NULL; scmnd->request_buffer = NULL;
SCpnt->request_bufflen = 0; scmnd->request_bufflen = 0;
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ scmnd->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->old_use_sg = 0; scmnd->old_use_sg = 0;
SCpnt->transfersize = 0; /* No default transfer size */ scmnd->transfersize = 0; /* No default transfer size */
SCpnt->cmd_len = 0; scmnd->cmd_len = 0;
SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; scmnd->sc_data_direction = SCSI_DATA_UNKNOWN;
SCpnt->sc_request = NULL; scmnd->sc_request = NULL;
SCpnt->sc_magic = SCSI_CMND_MAGIC; scmnd->sc_magic = SCSI_CMND_MAGIC;
SCpnt->result = 0; scmnd->result = 0;
SCpnt->underflow = 0; /* Do not flag underflow conditions */ scmnd->underflow = 0; /* Do not flag underflow conditions */
SCpnt->old_underflow = 0; scmnd->old_underflow = 0;
SCpnt->resid = 0; scmnd->resid = 0;
SCpnt->state = SCSI_STATE_INITIALIZING; scmnd->state = SCSI_STATE_INITIALIZING;
SCpnt->owner = SCSI_OWNER_HIGHLEVEL; scmnd->owner = SCSI_OWNER_HIGHLEVEL;
spin_unlock_irqrestore(&device_request_lock, flags); spin_unlock_irqrestore(&device_request_lock, flags);
SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
SCpnt->target, scmnd->target,
atomic_read(&SCpnt->host->host_active))); atomic_read(&scmnd->host->host_active)));
return SCpnt; return scmnd;
fail:
spin_unlock_irqrestore(&device_request_lock, flags);
return NULL;
} }
inline void __scsi_release_command(Scsi_Cmnd * SCpnt) inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
......
...@@ -16,22 +16,9 @@ ...@@ -16,22 +16,9 @@
#define _SCSI_H #define _SCSI_H
#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */ #include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h> /* some morons don't know struct pointers */
#include <linux/proc_fs.h>
#include <linux/init.h>
/*
* Some of the public constants are being moved to this file.
* We include it here so that what came from where is transparent.
*/
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <linux/random.h>
#include <asm/hardirq.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
/* /*
* These are the values that the SCpnt->sc_data_direction and * These are the values that the SCpnt->sc_data_direction and
...@@ -396,6 +383,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; ...@@ -396,6 +383,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
* Forward-declaration of structs for prototypes. * Forward-declaration of structs for prototypes.
*/ */
struct Scsi_Host; struct Scsi_Host;
struct scatterlist;
/* /*
* Add some typedefs so that we can prototyope a bunch of the functions. * Add some typedefs so that we can prototyope a bunch of the functions.
...@@ -445,10 +433,6 @@ void scsi_free_sgtable(struct scatterlist *sgl, int index); ...@@ -445,10 +433,6 @@ void scsi_free_sgtable(struct scatterlist *sgl, int index);
* Prototypes for functions in scsi_lib.c * Prototypes for functions in scsi_lib.c
*/ */
extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt); extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt);
extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate,
int sectors);
extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt); extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int); extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
...@@ -471,7 +455,7 @@ extern void scsi_slave_detach(struct scsi_device *sdev); ...@@ -471,7 +455,7 @@ 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 *);
extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int, int); extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int);
extern void __scsi_release_command(Scsi_Cmnd *); extern void __scsi_release_command(Scsi_Cmnd *);
extern void scsi_release_command(Scsi_Cmnd *); extern void scsi_release_command(Scsi_Cmnd *);
extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
...@@ -525,6 +509,8 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *); ...@@ -525,6 +509,8 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *);
extern struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *, extern struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *,
uint, uint, uint); uint, uint, uint);
extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_sdev(struct scsi_device *);
extern int scsi_add_single_device(uint, uint, uint, uint);
extern int scsi_remove_single_device(uint, uint, uint, uint);
/* /*
* Prototypes for functions in constants.c * Prototypes for functions in constants.c
...@@ -551,7 +537,7 @@ struct dev_info { ...@@ -551,7 +537,7 @@ struct dev_info {
unsigned flags; unsigned flags;
}; };
extern struct dev_info scsi_static_device_list[] __initdata; extern struct dev_info scsi_static_device_list[];
/* /*
* scsi_dev_info_list: structure to hold black/white listed devices. * scsi_dev_info_list: structure to hold black/white listed devices.
......
...@@ -95,7 +95,7 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head) ...@@ -95,7 +95,7 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
* fields related to error handling. Typically this will * fields related to error handling. Typically this will
* be called once for each command, as required. * be called once for each command, as required.
*/ */
int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt) static int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
{ {
SCpnt->owner = SCSI_OWNER_MIDLEVEL; SCpnt->owner = SCSI_OWNER_MIDLEVEL;
SCpnt->reset_chain = NULL; SCpnt->reset_chain = NULL;
...@@ -306,11 +306,10 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt) ...@@ -306,11 +306,10 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
* We are guaranteeing that the request queue will be goosed * We are guaranteeing that the request queue will be goosed
* at some point during this call. * at some point during this call.
*/ */
static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, static Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt,
int uptodate, int uptodate,
int sectors, int sectors,
int requeue, int requeue)
int frequeue)
{ {
request_queue_t *q = &SCpnt->device->request_queue; request_queue_t *q = &SCpnt->device->request_queue;
struct request *req = SCpnt->request; struct request *req = SCpnt->request;
...@@ -337,12 +336,9 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, ...@@ -337,12 +336,9 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
add_disk_randomness(req->rq_disk); add_disk_randomness(req->rq_disk);
spin_lock_irqsave(q->queue_lock, flags); spin_lock_irqsave(q->queue_lock, flags);
if (blk_rq_tagged(req)) if (blk_rq_tagged(req))
blk_queue_end_tag(q, req); blk_queue_end_tag(q, req);
end_that_request_last(req); end_that_request_last(req);
spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags);
/* /*
...@@ -350,38 +346,10 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, ...@@ -350,38 +346,10 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
* need to worry about launching another command. * need to worry about launching another command.
*/ */
__scsi_release_command(SCpnt); __scsi_release_command(SCpnt);
if (frequeue)
scsi_queue_next_request(q, NULL); scsi_queue_next_request(q, NULL);
return NULL; return NULL;
} }
/*
* Function: scsi_end_request()
*
* Purpose: Post-processing of completed commands called from interrupt
* handler or a bottom-half handler.
*
* Arguments: SCpnt - command that is complete.
* uptodate - 1 if I/O indicates success, 0 for I/O error.
* sectors - number of sectors we want to mark.
*
* Lock status: Assumed that lock is not held upon entry.
*
* Returns: Nothing
*
* Notes: This is called for block device requests in order to
* mark some number of sectors as complete.
*
* We are guaranteeing that the request queue will be goosed
* at some point during this call.
*/
Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
{
return __scsi_end_request(SCpnt, uptodate, sectors, 1, 1);
}
/* /*
* Function: scsi_release_buffers() * Function: scsi_release_buffers()
* *
...@@ -428,6 +396,29 @@ static void scsi_release_buffers(Scsi_Cmnd * SCpnt) ...@@ -428,6 +396,29 @@ static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
SCpnt->request_bufflen = 0; SCpnt->request_bufflen = 0;
} }
/*
* Function: scsi_get_request_dev()
*
* Purpose: Find the upper-level driver that is responsible for this
* request
*
* Arguments: request - I/O request we are preparing to queue.
*
* Lock status: No locks assumed to be held, but as it happens the
* q->queue_lock is held when this is called.
*
* Returns: Nothing
*
* Notes: The requests in the request queue may have originated
* from any block device driver. We need to find out which
* one so that we can later form the appropriate command.
*/
static struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
{
struct gendisk *p = req->rq_disk;
return p ? *(struct Scsi_Device_Template **)p->private_data : NULL;
}
/* /*
* Function: scsi_io_completion() * Function: scsi_io_completion()
* *
...@@ -527,11 +518,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -527,11 +518,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
* requeueing right here - we will requeue down below * requeueing right here - we will requeue down below
* when we handle the bad sectors. * when we handle the bad sectors.
*/ */
SCpnt = __scsi_end_request(SCpnt, SCpnt = scsi_end_request(SCpnt, 1, good_sectors, result == 0);
1,
good_sectors,
result == 0,
1);
/* /*
* If the command completed without error, then either finish off the * If the command completed without error, then either finish off the
...@@ -574,7 +561,8 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -574,7 +561,8 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
* and quietly refuse further access. * and quietly refuse further access.
*/ */
SCpnt->device->changed = 1; SCpnt->device->changed = 1;
SCpnt = scsi_end_request(SCpnt, 0, this_count); SCpnt = scsi_end_request(SCpnt, 0,
this_count, 1);
return; return;
} else { } else {
/* /*
...@@ -606,14 +594,14 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -606,14 +594,14 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
scsi_queue_next_request(q, SCpnt); scsi_queue_next_request(q, SCpnt);
result = 0; result = 0;
} else { } else {
SCpnt = scsi_end_request(SCpnt, 0, this_count); SCpnt = scsi_end_request(SCpnt, 0, this_count, 1);
return; return;
} }
break; break;
case NOT_READY: case NOT_READY:
printk(KERN_INFO "Device %s not ready.\n", printk(KERN_INFO "Device %s not ready.\n",
req->rq_disk ? req->rq_disk->disk_name : ""); req->rq_disk ? req->rq_disk->disk_name : "");
SCpnt = scsi_end_request(SCpnt, 0, this_count); SCpnt = scsi_end_request(SCpnt, 0, this_count, 1);
return; return;
break; break;
case MEDIUM_ERROR: case MEDIUM_ERROR:
...@@ -623,7 +611,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -623,7 +611,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
(int) SCpnt->target, (int) SCpnt->lun); (int) SCpnt->target, (int) SCpnt->lun);
print_command(SCpnt->data_cmnd); print_command(SCpnt->data_cmnd);
print_sense("sd", SCpnt); print_sense("sd", SCpnt);
SCpnt = scsi_end_request(SCpnt, 0, block_sectors); SCpnt = scsi_end_request(SCpnt, 0, block_sectors, 1);
return; return;
default: default:
break; break;
...@@ -656,34 +644,11 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -656,34 +644,11 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
* We sometimes get this cruft in the event that a medium error * We sometimes get this cruft in the event that a medium error
* isn't properly reported. * isn't properly reported.
*/ */
SCpnt = scsi_end_request(SCpnt, 0, req->current_nr_sectors); SCpnt = scsi_end_request(SCpnt, 0, req->current_nr_sectors, 1);
return; return;
} }
} }
/*
* Function: scsi_get_request_dev()
*
* Purpose: Find the upper-level driver that is responsible for this
* request
*
* Arguments: request - I/O request we are preparing to queue.
*
* Lock status: No locks assumed to be held, but as it happens the
* q->queue_lock is held when this is called.
*
* Returns: Nothing
*
* Notes: The requests in the request queue may have originated
* from any block device driver. We need to find out which
* one so that we can later form the appropriate command.
*/
struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
{
struct gendisk *p = req->rq_disk;
return p ? *(struct Scsi_Device_Template **)p->private_data : NULL;
}
/* /*
* Function: scsi_init_io() * Function: scsi_init_io()
* *
...@@ -763,7 +728,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt) ...@@ -763,7 +728,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
/* /*
* kill it. there should be no leftover blocks in this request * kill it. there should be no leftover blocks in this request
*/ */
SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors); SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors, 1);
BUG_ON(SCpnt); BUG_ON(SCpnt);
ret = BLKPREP_KILL; ret = BLKPREP_KILL;
out: out:
...@@ -797,8 +762,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -797,8 +762,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
SRpnt = (Scsi_Request *) req->special; SRpnt = (Scsi_Request *) req->special;
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) { if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
SCpnt = scsi_allocate_device(SRpnt->sr_device, SCpnt = scsi_allocate_device(SRpnt->sr_device, 0);
FALSE, FALSE);
if (!SCpnt) if (!SCpnt)
return BLKPREP_DEFER; return BLKPREP_DEFER;
scsi_init_cmd_from_req(SCpnt, SRpnt); scsi_init_cmd_from_req(SCpnt, SRpnt);
...@@ -811,7 +775,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -811,7 +775,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
if (req->special) { if (req->special) {
SCpnt = (Scsi_Cmnd *) req->special; SCpnt = (Scsi_Cmnd *) req->special;
} else { } else {
SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE); SCpnt = scsi_allocate_device(SDpnt, 0);
} }
/* /*
* if command allocation failure, wait a bit * if command allocation failure, wait a bit
......
...@@ -399,11 +399,8 @@ static void scsi_dump_status(int level) ...@@ -399,11 +399,8 @@ static void scsi_dump_status(int level)
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)
{ {
Scsi_Device *sdev;
struct Scsi_Host *shost;
char *p;
int host, channel, id, lun; int host, channel, id, lun;
char * buffer; char *buffer, *p;
int err; int err;
if (!buf || length>PAGE_SIZE) if (!buf || length>PAGE_SIZE)
...@@ -529,35 +526,9 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -529,35 +526,9 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
id = simple_strtoul(p + 1, &p, 0); id = simple_strtoul(p + 1, &p, 0);
lun = simple_strtoul(p + 1, &p, 0); lun = simple_strtoul(p + 1, &p, 0);
printk(KERN_INFO "scsi singledevice %d %d %d %d\n", host, channel, err = scsi_add_single_device(host, channel, id, lun);
id, lun); if (err >= 0)
for (shost = scsi_host_get_next(NULL); shost;
shost = scsi_host_get_next(shost)) {
if (shost->host_no == host) {
break;
}
}
err = -ENXIO;
if (!shost)
goto out;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
if ((sdev->channel == channel
&& sdev->id == id
&& sdev->lun == lun)) {
break;
}
}
err = -ENOSYS;
if (sdev)
goto out; /* We do not yet support unplugging */
scan_scsis(shost, 1, channel, id, lun);
err = length; err = length;
goto out;
}
/* /*
* Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
* with "0 1 2 3" replaced by your "Host Channel Id Lun". * with "0 1 2 3" replaced by your "Host Channel Id Lun".
...@@ -569,7 +540,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -569,7 +540,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
* hardware and thoroughly confuse the SCSI subsystem. * hardware and thoroughly confuse the SCSI subsystem.
* *
*/ */
else if (!strncmp("remove-single-device", buffer + 5, 20)) { } else if (!strncmp("remove-single-device", buffer + 5, 20)) {
p = buffer + 26; p = buffer + 26;
host = simple_strtoul(p, &p, 0); host = simple_strtoul(p, &p, 0);
...@@ -577,39 +548,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, ...@@ -577,39 +548,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
id = simple_strtoul(p + 1, &p, 0); id = simple_strtoul(p + 1, &p, 0);
lun = simple_strtoul(p + 1, &p, 0); lun = simple_strtoul(p + 1, &p, 0);
err = scsi_remove_single_device(host, channel, id, lun);
for (shost = scsi_host_get_next(NULL); shost;
shost = scsi_host_get_next(shost)) {
if (shost->host_no == host) {
break;
}
}
err = -ENODEV;
if (!shost)
goto out;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
if ((sdev->channel == channel
&& sdev->id == id
&& sdev->lun == lun)) {
break;
}
}
if (sdev == NULL)
goto out; /* there is no such device attached */
err = -EBUSY;
if (sdev->access_count)
goto out;
scsi_detach_device(sdev);
if (sdev->attached == 0) {
devfs_unregister (sdev->de);
scsi_free_sdev(sdev);
err = 0;
}
} }
out: out:
......
...@@ -1862,6 +1862,69 @@ static int scsi_report_lun_scan(Scsi_Device *sdevscan) ...@@ -1862,6 +1862,69 @@ static int scsi_report_lun_scan(Scsi_Device *sdevscan)
} }
int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
{
struct scsi_device *sdevscan, *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 = -ENOMEM;
sdevscan = scsi_alloc_sdev(shost, channel, id, lun);
if (!sdevscan)
goto out;
sdevscan->scsi_level = scsi_find_scsi_level(channel, id, shost);
error = scsi_probe_and_add_lun(sdevscan, &sdev, NULL);
scsi_free_sdev(sdevscan);
error = -ENODEV;
if (error != SCSI_SCAN_LUN_PRESENT)
goto out;
scsi_attach_device(sdev);
error = 0;
out:
scsi_host_put(shost);
return error;
}
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;
error = -EBUSY;
if (sdev->access_count)
goto out;
scsi_detach_device(sdev);
if (sdev->attached)
goto out;
devfs_unregister(sdev->de);
scsi_free_sdev(sdev);
error = 0;
out:
scsi_host_put(shost);
return error;
}
/** /**
* scsi_scan_target - scan a target id, possibly including all LUNs on the * scsi_scan_target - scan a target id, possibly including all LUNs on the
* target. * target.
...@@ -1927,71 +1990,17 @@ static void scsi_scan_target(Scsi_Device *sdevscan, struct Scsi_Host *shost, ...@@ -1927,71 +1990,17 @@ static void scsi_scan_target(Scsi_Device *sdevscan, struct Scsi_Host *shost,
} }
/** /**
* scsi_scan_selected_lun - probe and add one LUN * scsi_scan_host - scan the given adapter
*
* Description:
* Probe a single LUN on @shost, @channel, @id and @lun. If the LUN is
* found, set the queue depth, allocate command blocks, and call
* init/attach/finish of the upper level (sd, sg, etc.) drivers.
**/
static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
uint id, uint lun)
{
Scsi_Device *sdevscan, *sdev = NULL;
int res;
if ((channel > shost->max_channel) || (id >= shost->max_id) ||
(lun >= shost->max_lun))
return;
sdevscan = scsi_alloc_sdev(shost, channel, id, lun);
if (sdevscan == NULL)
return;
sdevscan->scsi_level = scsi_find_scsi_level(channel, id, shost);
res = scsi_probe_and_add_lun(sdevscan, &sdev, NULL);
scsi_free_sdev(sdevscan);
if (res != SCSI_SCAN_LUN_PRESENT)
return;
scsi_attach_device(sdev);
}
/**
* scan_scsis - scan the given adapter, or scan a single LUN
* @shost: adapter to scan * @shost: adapter to scan
* @hardcoded: 1 if a single channel/id/lun should be scanned, else 0
* @hchannel: channel to scan for hardcoded case
* @hid: target id to scan for hardcoded case
* @hlun: lun to scan for hardcoded case
* *
* Description: * Description:
* If @hardcoded is 1, call scsi_scan_selected_lun to scan a single * Iterate and call scsi_scan_target to scan all possible target id's
* LUN; else, iterate and call scsi_scan_target to scan all possible * on all possible channels.
* target id's on all possible channels.
**/ **/
void scan_scsis(struct Scsi_Host *shost, uint hardcoded, uint hchannel, void scsi_scan_host(struct Scsi_Host *shost)
uint hid, uint hlun)
{ {
if (hardcoded == 1) { struct scsi_device *sdevscan;
/* uint channel, id, order_id;
* XXX Overload hchannel/hid/hlun to figure out what to
* scan, and use the standard scanning code rather than
* this function - that way, an entire bus (or fabric), or
* target id can be scanned. There are problems with queue
* depth and the init/attach/finish that must be resolved
* before (re-)scanning can handle finding more than one new
* LUN.
*
* For example, set hchannel 0 and hid to 5, and hlun to -1
* in order to scan all LUNs on channel 0, target id 5.
*/
scsi_scan_selected_lun(shost, hchannel, hid, hlun);
} else {
Scsi_Device *sdevscan;
uint channel;
unsigned int id, order_id;
/* /*
* The blk layer queue allocation is a bit expensive to * The blk layer queue allocation is a bit expensive to
...@@ -2033,5 +2042,4 @@ void scan_scsis(struct Scsi_Host *shost, uint hardcoded, uint hchannel, ...@@ -2033,5 +2042,4 @@ void scan_scsis(struct Scsi_Host *shost, uint hardcoded, uint hchannel,
} }
} }
scsi_free_sdev(sdevscan); scsi_free_sdev(sdevscan);
}
} }
...@@ -75,7 +75,6 @@ EXPORT_SYMBOL(scsi_free_host_dev); ...@@ -75,7 +75,6 @@ EXPORT_SYMBOL(scsi_free_host_dev);
EXPORT_SYMBOL(scsi_sleep); EXPORT_SYMBOL(scsi_sleep);
EXPORT_SYMBOL(scsi_io_completion); EXPORT_SYMBOL(scsi_io_completion);
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);
......
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