unsigned long timeout;
int rtn = 0;
+ /* check if the device is still usable */
+ if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
+ /* in SDEV_DEL we error all commands. DID_NO_CONNECT
+ * returns an immediate error upwards, and signals
+ * that the device is no longer present */
+ cmd->result = DID_NO_CONNECT << 16;
+ scsi_done(cmd);
+ /* return 0 (because the command has been processed) */
+ goto out;
+ }
/* Assign a unique nonzero serial_number. */
/* XXX(hch): this is racy */
if (++serial_number == 0)
*/
int scsi_device_get(struct scsi_device *sdev)
{
- if (test_bit(SDEV_DEL, &sdev->sdev_state))
+ if (sdev->sdev_state == SDEV_DEL)
return -ENXIO;
if (!get_device(&sdev->sdev_gendev))
return -ENXIO;
struct list_head *lh, *lh_sf;
unsigned long flags;
- set_bit(SDEV_CANCEL, &sdev->sdev_state);
+ sdev->sdev_state = SDEV_CANCEL;
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
{
struct scsi_device *sdev = q->queuedata;
struct scsi_cmnd *cmd;
+ int specials_only = 0;
+
+ if(unlikely(sdev->sdev_state != SDEV_RUNNING)) {
+ /* OK, we're not in a running state don't prep
+ * user commands */
+ if(sdev->sdev_state == SDEV_DEL) {
+ /* Device is fully deleted, no commands
+ * at all allowed down */
+ printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
+ sdev->host->host_no, sdev->id, sdev->lun);
+ return BLKPREP_KILL;
+ }
+ /* OK, we only allow special commands (i.e. not
+ * user initiated ones */
+ specials_only = 1;
+ }
/*
* Find the actual device driver associated with this command.
} else
cmd = req->special;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+
+ if(unlikely(specials_only)) {
+ printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
+ sdev->host->host_no, sdev->id, sdev->lun);
+ return BLKPREP_KILL;
+ }
+
+
/*
* Just check to see if the device is online. If
* it isn't, we refuse to process ordinary commands
struct scsi_cmnd *cmd;
struct request *req;
+ if(!get_device(&sdev->sdev_gendev))
+ /* We must be tearing the block queue down already */
+ return;
+
/*
* To start with, we keep looping until the queue is empty, or until
* the host is no longer able to accept any more requests.
}
}
- return;
+ goto out;
not_ready:
spin_unlock_irq(shost->host_lock);
sdev->device_busy--;
if(sdev->device_busy == 0)
blk_plug_device(q);
+ out:
+ /* must be careful here...if we trigger the ->remove() function
+ * we cannot be holding the q lock */
+ spin_unlock_irq(q->queue_lock);
+ put_device(&sdev->sdev_gendev);
+ spin_lock_irq(q->queue_lock);
}
u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
sdev->lun = lun;
sdev->channel = channel;
sdev->online = TRUE;
+ sdev->sdev_state = SDEV_CREATED;
INIT_LIST_HEAD(&sdev->siblings);
INIT_LIST_HEAD(&sdev->same_target_siblings);
INIT_LIST_HEAD(&sdev->cmd_list);
{
int error = -EINVAL, i;
- if (test_and_set_bit(SDEV_ADD, &sdev->sdev_state))
+ if (sdev->sdev_state != SDEV_CREATED)
return error;
+ sdev->sdev_state = SDEV_RUNNING;
+
error = device_add(&sdev->sdev_gendev);
if (error) {
printk(KERN_INFO "error 1\n");
return error;
clean_device:
+ sdev->sdev_state = SDEV_CANCEL;
+
device_del(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
+
return error;
}
**/
void scsi_remove_device(struct scsi_device *sdev)
{
- if (test_and_clear_bit(SDEV_ADD, &sdev->sdev_state)) {
- set_bit(SDEV_DEL, &sdev->sdev_state);
+ if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) {
+ sdev->sdev_state = SDEV_DEL;
class_device_unregister(&sdev->sdev_classdev);
device_del(&sdev->sdev_gendev);
if (sdev->host->hostt->slave_destroy)
/*
* sdev state
*/
-enum {
- SDEV_ADD,
- SDEV_DEL,
- SDEV_CANCEL,
- SDEV_RECOVERY,
+enum scsi_device_state {
+ SDEV_CREATED, /* device created but not added to sysfs
+ * Only internal commands allowed (for inq) */
+ SDEV_RUNNING, /* device properly configured
+ * All commands allowed */
+ SDEV_CANCEL, /* beginning to delete device
+ * Only error handler commands allowed */
+ SDEV_DEL, /* device deleted
+ * no commands allowed */
};
struct scsi_device {
struct device sdev_gendev;
struct class_device sdev_classdev;
- unsigned long sdev_state;
+ enum scsi_device_state sdev_state;
};
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)