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 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
......@@ -16,26 +16,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
*
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.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/blk.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/cdrom.h>
#include <linux/slab.h>
#include <linux/bio.h>
#include <asm/uaccess.h>
#include "../scsi/scsi.h"
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
#include <asm/uaccess.h>
/* Command group 3 is reserved and should never be used. */
const unsigned char scsi_command_size[8] =
......
......@@ -55,7 +55,6 @@
#include <linux/spinlock.h>
#include "scsi.h"
#include "hosts.h"
#include "NCR53c406a.h"
/* ============================================================= */
......
......@@ -1601,7 +1601,7 @@ return -ENOTSUPP;
scsi_cdb[0] = RELEASE;
// allocate with wait = true, interruptible = false
SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
SCpnt = scsi_allocate_device(ScsiDev, 1);
{
CPQFC_DECLARE_COMPLETION(wait);
......
......@@ -4599,7 +4599,7 @@ static void gdth_flush(int hanum)
#if LINUX_VERSION_CODE >= 0x020322
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->use_sg = 0;
#else
......@@ -4673,7 +4673,7 @@ void gdth_halt(void)
memset(cmnd, 0xff, MAX_COMMAND_SIZE);
#if LINUX_VERSION_CODE >= 0x020322
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->use_sg = 0;
#else
......
......@@ -48,7 +48,7 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
scp = scsi_allocate_device(sdev, 1, FALSE);
scp = scsi_allocate_device(sdev, 1);
if (!scp)
return -ENOMEM;
scp->cmd_len = 12;
......@@ -712,7 +712,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
scp = scsi_allocate_device(sdev, 1, FALSE);
scp = scsi_allocate_device(sdev, 1);
if (!scp)
return -ENOMEM;
scp->cmd_len = 12;
......
......@@ -208,6 +208,48 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost)
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
* @shost: a pointer to a scsi host to release
......@@ -218,7 +260,6 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost)
int scsi_remove_host(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
struct scsi_cmnd *scmd;
/*
* FIXME Do ref counting. We force all of the devices offline to
......@@ -228,43 +269,9 @@ int scsi_remove_host(struct Scsi_Host *shost)
for (sdev = shost->host_queue; sdev; sdev = sdev->next)
sdev->online = FALSE;
for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
/*
* 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");
for (sdev = shost->host_queue; sdev; sdev = sdev->next)
if (scsi_check_device_busy(sdev))
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
......@@ -308,7 +315,7 @@ int scsi_add_host(struct Scsi_Host *shost)
sht->info ? sht->info(shost) : sht->name);
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) {
if (sdev->host->hostt != sht)
......
......@@ -519,7 +519,7 @@ static inline void scsi_set_pci_device(struct Scsi_Host *shost,
/*
* 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
{
......
......@@ -974,13 +974,11 @@ static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb,
mega_ioctl_mbox * mbox);
#endif
static int megadev_open (struct inode *, struct file *);
static int megadev_ioctl_entry (struct inode *, struct file *,
unsigned int, unsigned long);
static int megadev_ioctl (struct inode *, struct file *,
unsigned int, unsigned long);
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 int mega_init_scb (mega_host_config *);
static void enq_scb_freelist (mega_host_config *, mega_scb *,
......
......@@ -346,6 +346,41 @@ void scsi_release_request(Scsi_Request * 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
*
......@@ -372,89 +407,30 @@ void scsi_release_request(Scsi_Request * req)
* This function is deprecated, and drivers should be
* rewritten to use Scsi_Request instead of Scsi_Cmnd.
*/
Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait,
int interruptable)
struct scsi_cmnd *scsi_allocate_device(struct scsi_device *sdev, int wait)
{
struct Scsi_Host *host;
Scsi_Cmnd *SCpnt = NULL;
Scsi_Device *SDpnt;
DECLARE_WAITQUEUE(wq, current);
struct Scsi_Host *shost = sdev->host;
struct scsi_cmnd *scmnd;
unsigned long flags;
if (!device)
panic("No device passed to scsi_allocate_device().\n");
host = device->host;
spin_lock_irqsave(&device_request_lock, flags);
while (1 == 1) {
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;
while (1) {
if (sdev->device_blocked)
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.
*/
for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) {
if (SCpnt->request == NULL)
break;
}
}
/*
* If we couldn't find a free command block, and we have been
* 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);
for (scmnd = sdev->device_queue; scmnd; scmnd = scmnd->next)
if (!scmnd->request)
goto found;
busy:
if (!wait)
goto fail;
/*
* 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,
* to schedule() wouldn't block (well, it might switch,
* but the current task will still be schedulable.
*/
add_wait_queue(&device->scpnt_wait, &wait);
if( interruptable ) {
set_current_state(TASK_INTERRUPTIBLE);
} else {
add_wait_queue(&sdev->scpnt_wait, &wq);
set_current_state(TASK_UNINTERRUPTIBLE);
}
spin_unlock_irqrestore(&device_request_lock, flags);
/*
* This should block until a device command block
* becomes available.
*/
schedule();
spin_lock_irqsave(&device_request_lock, flags);
remove_wait_queue(&device->scpnt_wait, &wait);
/*
* FIXME - Isn't this redundant?? Someone
* else will have forced the state back to running.
*/
remove_wait_queue(&sdev->scpnt_wait, &wq);
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;
atomic_inc(&SCpnt->host->host_active);
atomic_inc(&SCpnt->device->device_active);
found:
scmnd->request = NULL;
atomic_inc(&scmnd->host->host_active);
atomic_inc(&scmnd->device->device_active);
SCpnt->buffer = NULL;
SCpnt->bufflen = 0;
SCpnt->request_buffer = NULL;
SCpnt->request_bufflen = 0;
scmnd->buffer = NULL;
scmnd->bufflen = 0;
scmnd->request_buffer = NULL;
scmnd->request_bufflen = 0;
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0; /* No default transfer size */
SCpnt->cmd_len = 0;
scmnd->use_sg = 0; /* Reset the scatter-gather flag */
scmnd->old_use_sg = 0;
scmnd->transfersize = 0; /* No default transfer size */
scmnd->cmd_len = 0;
SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN;
SCpnt->sc_request = NULL;
SCpnt->sc_magic = SCSI_CMND_MAGIC;
scmnd->sc_data_direction = SCSI_DATA_UNKNOWN;
scmnd->sc_request = NULL;
scmnd->sc_magic = SCSI_CMND_MAGIC;
SCpnt->result = 0;
SCpnt->underflow = 0; /* Do not flag underflow conditions */
SCpnt->old_underflow = 0;
SCpnt->resid = 0;
SCpnt->state = SCSI_STATE_INITIALIZING;
SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
scmnd->result = 0;
scmnd->underflow = 0; /* Do not flag underflow conditions */
scmnd->old_underflow = 0;
scmnd->resid = 0;
scmnd->state = SCSI_STATE_INITIALIZING;
scmnd->owner = SCSI_OWNER_HIGHLEVEL;
spin_unlock_irqrestore(&device_request_lock, flags);
SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
SCpnt->target,
atomic_read(&SCpnt->host->host_active)));
scmnd->target,
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)
......
......@@ -16,22 +16,9 @@
#define _SCSI_H
#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
#include <linux/devfs_fs_kernel.h>
#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 <linux/devfs_fs_kernel.h> /* some morons don't know struct pointers */
#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
......@@ -396,6 +383,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
* Forward-declaration of structs for prototypes.
*/
struct Scsi_Host;
struct scatterlist;
/*
* 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);
* Prototypes for functions in scsi_lib.c
*/
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 int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
......@@ -471,7 +455,7 @@ extern void scsi_slave_detach(struct scsi_device *sdev);
extern void scsi_done(Scsi_Cmnd * SCpnt);
extern void scsi_finish_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_do_cmd(Scsi_Cmnd *, const void *cmnd,
......@@ -525,6 +509,8 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *);
extern struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *,
uint, uint, uint);
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
......@@ -551,7 +537,7 @@ struct dev_info {
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.
......
......@@ -95,7 +95,7 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
* fields related to error handling. Typically this will
* 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->reset_chain = NULL;
......@@ -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
* 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 sectors,
int requeue,
int frequeue)
int requeue)
{
request_queue_t *q = &SCpnt->device->request_queue;
struct request *req = SCpnt->request;
......@@ -337,12 +336,9 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
add_disk_randomness(req->rq_disk);
spin_lock_irqsave(q->queue_lock, flags);
if (blk_rq_tagged(req))
blk_queue_end_tag(q, req);
end_that_request_last(req);
spin_unlock_irqrestore(q->queue_lock, flags);
/*
......@@ -350,38 +346,10 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
* need to worry about launching another command.
*/
__scsi_release_command(SCpnt);
if (frequeue)
scsi_queue_next_request(q, 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()
*
......@@ -428,6 +396,29 @@ static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
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()
*
......@@ -527,11 +518,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
* requeueing right here - we will requeue down below
* when we handle the bad sectors.
*/
SCpnt = __scsi_end_request(SCpnt,
1,
good_sectors,
result == 0,
1);
SCpnt = scsi_end_request(SCpnt, 1, good_sectors, result == 0);
/*
* 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,
* and quietly refuse further access.
*/
SCpnt->device->changed = 1;
SCpnt = scsi_end_request(SCpnt, 0, this_count);
SCpnt = scsi_end_request(SCpnt, 0,
this_count, 1);
return;
} else {
/*
......@@ -606,14 +594,14 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
scsi_queue_next_request(q, SCpnt);
result = 0;
} else {
SCpnt = scsi_end_request(SCpnt, 0, this_count);
SCpnt = scsi_end_request(SCpnt, 0, this_count, 1);
return;
}
break;
case NOT_READY:
printk(KERN_INFO "Device %s not ready.\n",
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;
break;
case MEDIUM_ERROR:
......@@ -623,7 +611,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
(int) SCpnt->target, (int) SCpnt->lun);
print_command(SCpnt->data_cmnd);
print_sense("sd", SCpnt);
SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
SCpnt = scsi_end_request(SCpnt, 0, block_sectors, 1);
return;
default:
break;
......@@ -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
* 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;
}
}
/*
* 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()
*
......@@ -763,7 +728,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
/*
* 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);
ret = BLKPREP_KILL;
out:
......@@ -797,8 +762,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
SRpnt = (Scsi_Request *) req->special;
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
SCpnt = scsi_allocate_device(SRpnt->sr_device,
FALSE, FALSE);
SCpnt = scsi_allocate_device(SRpnt->sr_device, 0);
if (!SCpnt)
return BLKPREP_DEFER;
scsi_init_cmd_from_req(SCpnt, SRpnt);
......@@ -811,7 +775,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
if (req->special) {
SCpnt = (Scsi_Cmnd *) req->special;
} else {
SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE);
SCpnt = scsi_allocate_device(SDpnt, 0);
}
/*
* if command allocation failure, wait a bit
......
......@@ -399,11 +399,8 @@ static void scsi_dump_status(int level)
static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data)
{
Scsi_Device *sdev;
struct Scsi_Host *shost;
char *p;
int host, channel, id, lun;
char * buffer;
char *buffer, *p;
int err;
if (!buf || length>PAGE_SIZE)
......@@ -529,35 +526,9 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
id = 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,
id, lun);
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 = scsi_add_single_device(host, channel, id, lun);
if (err >= 0)
err = length;
goto out;
}
/*
* 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".
......@@ -569,7 +540,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
* 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;
host = simple_strtoul(p, &p, 0);
......@@ -577,39 +548,7 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
id = simple_strtoul(p + 1, &p, 0);
lun = simple_strtoul(p + 1, &p, 0);
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;
}
err = scsi_remove_single_device(host, channel, id, lun);
}
out:
......
......@@ -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
* target.
......@@ -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
*
* 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
* scsi_scan_host - scan the given adapter
* @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:
* If @hardcoded is 1, call scsi_scan_selected_lun to scan a single
* LUN; else, iterate and call scsi_scan_target to scan all possible
* target id's on all possible channels.
* Iterate and call scsi_scan_target to scan all possible target id's
* on all possible channels.
**/
void scan_scsis(struct Scsi_Host *shost, uint hardcoded, uint hchannel,
uint hid, uint hlun)
void scsi_scan_host(struct Scsi_Host *shost)
{
if (hardcoded == 1) {
/*
* 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;
struct scsi_device *sdevscan;
uint channel, id, order_id;
/*
* 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,
}
}
scsi_free_sdev(sdevscan);
}
}
......@@ -75,7 +75,6 @@ EXPORT_SYMBOL(scsi_free_host_dev);
EXPORT_SYMBOL(scsi_sleep);
EXPORT_SYMBOL(scsi_io_completion);
EXPORT_SYMBOL(scsi_end_request);
EXPORT_SYMBOL(scsi_register_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