diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/scsi_lib.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 2023 |
1 files changed, 2023 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c new file mode 100644 index 00000000000..7cbc4127fb5 --- /dev/null +++ b/drivers/scsi/scsi_lib.c @@ -0,0 +1,2023 @@ +/* + * scsi_lib.c Copyright (C) 1999 Eric Youngdale + * + * SCSI queueing library. + * Initial versions: Eric Youngdale (eric@andante.org). + * Based upon conversations with large numbers + * of people at Linux Expo. + */ + +#include <linux/bio.h> +#include <linux/blkdev.h> +#include <linux/completion.h> +#include <linux/kernel.h> +#include <linux/mempool.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_dbg.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_driver.h> +#include <scsi/scsi_eh.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_request.h> + +#include "scsi_priv.h" +#include "scsi_logging.h" + + +#define SG_MEMPOOL_NR (sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool)) +#define SG_MEMPOOL_SIZE 32 + +struct scsi_host_sg_pool { + size_t size; + char *name; + kmem_cache_t *slab; + mempool_t *pool; +}; + +#if (SCSI_MAX_PHYS_SEGMENTS < 32) +#error SCSI_MAX_PHYS_SEGMENTS is too small +#endif + +#define SP(x) { x, "sgpool-" #x } +struct scsi_host_sg_pool scsi_sg_pools[] = { + SP(8), + SP(16), + SP(32), +#if (SCSI_MAX_PHYS_SEGMENTS > 32) + SP(64), +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + SP(128), +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + SP(256), +#if (SCSI_MAX_PHYS_SEGMENTS > 256) +#error SCSI_MAX_PHYS_SEGMENTS is too large +#endif +#endif +#endif +#endif +}; +#undef SP + + +/* + * Function: scsi_insert_special_req() + * + * Purpose: Insert pre-formed request into request queue. + * + * Arguments: sreq - request that is ready to be queued. + * at_head - boolean. True if we should insert at head + * of queue, false if we should insert at tail. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: Nothing + * + * Notes: This function is called from character device and from + * ioctl types of functions where the caller knows exactly + * what SCSI command needs to be issued. The idea is that + * we merely inject the command into the queue (at the head + * for now), and then call the queue request function to actually + * process it. + */ +int scsi_insert_special_req(struct scsi_request *sreq, int at_head) +{ + /* + * Because users of this function are apt to reuse requests with no + * modification, we have to sanitise the request flags here + */ + sreq->sr_request->flags &= ~REQ_DONTPREP; + blk_insert_request(sreq->sr_device->request_queue, sreq->sr_request, + at_head, sreq, 0); + return 0; +} + +/* + * Function: scsi_queue_insert() + * + * Purpose: Insert a command in the midlevel queue. + * + * Arguments: cmd - command that we are adding to queue. + * reason - why we are inserting command to queue. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: Nothing. + * + * Notes: We do this for one of two cases. Either the host is busy + * and it cannot accept any more commands for the time being, + * or the device returned QUEUE_FULL and can accept no more + * commands. + * Notes: This could be called either from an interrupt context or a + * normal process context. + */ +int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +{ + struct Scsi_Host *host = cmd->device->host; + struct scsi_device *device = cmd->device; + + SCSI_LOG_MLQUEUE(1, + printk("Inserting command %p into mlqueue\n", cmd)); + + /* + * We are inserting the command into the ml queue. First, we + * cancel the timer, so it doesn't time out. + */ + scsi_delete_timer(cmd); + + /* + * Next, set the appropriate busy bit for the device/host. + * + * If the host/device isn't busy, assume that something actually + * completed, and that we should be able to queue a command now. + * + * Note that the prior mid-layer assumption that any host could + * always queue at least one command is now broken. The mid-layer + * will implement a user specifiable stall (see + * scsi_host.max_host_blocked and scsi_device.max_device_blocked) + * if a command is requeued with no other commands outstanding + * either for the device or for the host. + */ + if (reason == SCSI_MLQUEUE_HOST_BUSY) + host->host_blocked = host->max_host_blocked; + else if (reason == SCSI_MLQUEUE_DEVICE_BUSY) + device->device_blocked = device->max_device_blocked; + + /* + * Register the fact that we own the thing for now. + */ + cmd->state = SCSI_STATE_MLQUEUE; + cmd->owner = SCSI_OWNER_MIDLEVEL; + + /* + * Decrement the counters, since these commands are no longer + * active on the host/device. + */ + scsi_device_unbusy(device); + + /* + * Insert this command at the head of the queue for it's device. + * It will go before all other commands that are already in the queue. + * + * NOTE: there is magic here about the way the queue is plugged if + * we have no outstanding commands. + * + * Although this *doesn't* plug the queue, it does call the request + * function. The SCSI request function detects the blocked condition + * and plugs the queue appropriately. + */ + blk_insert_request(device->request_queue, cmd->request, 1, cmd, 1); + return 0; +} + +/* + * Function: scsi_do_req + * + * Purpose: Queue a SCSI request + * + * Arguments: sreq - command descriptor. + * cmnd - actual SCSI command to be performed. + * buffer - data buffer. + * bufflen - size of data buffer. + * done - completion function to be run. + * timeout - how long to let it run before timeout. + * retries - number of retries we allow. + * + * Lock status: No locks held upon entry. + * + * Returns: Nothing. + * + * Notes: This function is only used for queueing requests for things + * like ioctls and character device requests - this is because + * we essentially just inject a request into the queue for the + * device. + * + * In order to support the scsi_device_quiesce function, we + * now inject requests on the *head* of the device queue + * rather than the tail. + */ +void scsi_do_req(struct scsi_request *sreq, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done)(struct scsi_cmnd *), + int timeout, int retries) +{ + /* + * If the upper level driver is reusing these things, then + * we should release the low-level block now. Another one will + * be allocated later when this request is getting queued. + */ + __scsi_release_request(sreq); + + /* + * Our own function scsi_done (which marks the host as not busy, + * disables the timeout counter, etc) will be called by us or by the + * scsi_hosts[host].queuecommand() function needs to also call + * the completion function for the high level driver. + */ + memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd)); + sreq->sr_bufflen = bufflen; + sreq->sr_buffer = buffer; + sreq->sr_allowed = retries; + sreq->sr_done = done; + sreq->sr_timeout_per_command = timeout; + + if (sreq->sr_cmd_len == 0) + sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]); + + /* + * head injection *required* here otherwise quiesce won't work + */ + scsi_insert_special_req(sreq, 1); +} +EXPORT_SYMBOL(scsi_do_req); + +static void scsi_wait_done(struct scsi_cmnd *cmd) +{ + struct request *req = cmd->request; + struct request_queue *q = cmd->device->request_queue; + unsigned long flags; + + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + + spin_lock_irqsave(q->queue_lock, flags); + if (blk_rq_tagged(req)) + blk_queue_end_tag(q, req); + spin_unlock_irqrestore(q->queue_lock, flags); + + if (req->waiting) + complete(req->waiting); +} + +/* This is the end routine we get to if a command was never attached + * to the request. Simply complete the request without changing + * rq_status; this will cause a DRIVER_ERROR. */ +static void scsi_wait_req_end_io(struct request *req) +{ + BUG_ON(!req->waiting); + + complete(req->waiting); +} + +void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, + unsigned bufflen, int timeout, int retries) +{ + DECLARE_COMPLETION(wait); + + sreq->sr_request->waiting = &wait; + sreq->sr_request->rq_status = RQ_SCSI_BUSY; + sreq->sr_request->end_io = scsi_wait_req_end_io; + scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done, + timeout, retries); + wait_for_completion(&wait); + sreq->sr_request->waiting = NULL; + if (sreq->sr_request->rq_status != RQ_SCSI_DONE) + sreq->sr_result |= (DRIVER_ERROR << 24); + + __scsi_release_request(sreq); +} +EXPORT_SYMBOL(scsi_wait_req); + +/* + * Function: scsi_init_cmd_errh() + * + * Purpose: Initialize cmd fields related to error handling. + * + * Arguments: cmd - command that is ready to be queued. + * + * Returns: Nothing + * + * Notes: This function has the job of initializing a number of + * fields related to error handling. Typically this will + * be called once for each command, as required. + */ +static int scsi_init_cmd_errh(struct scsi_cmnd *cmd) +{ + cmd->owner = SCSI_OWNER_MIDLEVEL; + cmd->serial_number = 0; + cmd->serial_number_at_timeout = 0; + cmd->abort_reason = 0; + + memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer); + + if (cmd->cmd_len == 0) + cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); + + /* + * We need saved copies of a number of fields - this is because + * error handling may need to overwrite these with different values + * to run different commands, and once error handling is complete, + * we will need to restore these values prior to running the actual + * command. + */ + cmd->old_use_sg = cmd->use_sg; + cmd->old_cmd_len = cmd->cmd_len; + cmd->sc_old_data_direction = cmd->sc_data_direction; + cmd->old_underflow = cmd->underflow; + memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd)); + cmd->buffer = cmd->request_buffer; + cmd->bufflen = cmd->request_bufflen; + cmd->internal_timeout = NORMAL_TIMEOUT; + cmd->abort_reason = 0; + + return 1; +} + +/* + * Function: scsi_setup_cmd_retry() + * + * Purpose: Restore the command state for a retry + * + * Arguments: cmd - command to be restored + * + * Returns: Nothing + * + * Notes: Immediately prior to retrying a command, we need + * to restore certain fields that we saved above. + */ +void scsi_setup_cmd_retry(struct scsi_cmnd *cmd) +{ + memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd)); + cmd->request_buffer = cmd->buffer; + cmd->request_bufflen = cmd->bufflen; + cmd->use_sg = cmd->old_use_sg; + cmd->cmd_len = cmd->old_cmd_len; + cmd->sc_data_direction = cmd->sc_old_data_direction; + cmd->underflow = cmd->old_underflow; +} + +void scsi_device_unbusy(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = sdev->host; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + shost->host_busy--; + if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) && + shost->host_failed)) + scsi_eh_wakeup(shost); + spin_unlock(shost->host_lock); + spin_lock(&sdev->sdev_lock); + sdev->device_busy--; + spin_unlock_irqrestore(&sdev->sdev_lock, flags); +} + +/* + * Called for single_lun devices on IO completion. Clear starget_sdev_user, + * and call blk_run_queue for all the scsi_devices on the target - + * including current_sdev first. + * + * Called with *no* scsi locks held. + */ +static void scsi_single_lun_run(struct scsi_device *current_sdev) +{ + struct Scsi_Host *shost = current_sdev->host; + struct scsi_device *sdev, *tmp; + struct scsi_target *starget = scsi_target(current_sdev); + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + starget->starget_sdev_user = NULL; + spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * Call blk_run_queue for all LUNs on the target, starting with + * current_sdev. We race with others (to set starget_sdev_user), + * but in most cases, we will be first. Ideally, each LU on the + * target would get some limited time or requests on the target. + */ + blk_run_queue(current_sdev->request_queue); + + spin_lock_irqsave(shost->host_lock, flags); + if (starget->starget_sdev_user) + goto out; + list_for_each_entry_safe(sdev, tmp, &starget->devices, + same_target_siblings) { + if (sdev == current_sdev) + continue; + if (scsi_device_get(sdev)) + continue; + + spin_unlock_irqrestore(shost->host_lock, flags); + blk_run_queue(sdev->request_queue); + spin_lock_irqsave(shost->host_lock, flags); + + scsi_device_put(sdev); + } + out: + spin_unlock_irqrestore(shost->host_lock, flags); +} + +/* + * Function: scsi_run_queue() + * + * Purpose: Select a proper request queue to serve next + * + * Arguments: q - last request's queue + * + * Returns: Nothing + * + * Notes: The previous command was completely finished, start + * a new one if possible. + */ +static void scsi_run_queue(struct request_queue *q) +{ + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; + unsigned long flags; + + if (sdev->single_lun) + scsi_single_lun_run(sdev); + + spin_lock_irqsave(shost->host_lock, flags); + while (!list_empty(&shost->starved_list) && + !shost->host_blocked && !shost->host_self_blocked && + !((shost->can_queue > 0) && + (shost->host_busy >= shost->can_queue))) { + /* + * As long as shost is accepting commands and we have + * starved queues, call blk_run_queue. scsi_request_fn + * drops the queue_lock and can add us back to the + * starved_list. + * + * host_lock protects the starved_list and starved_entry. + * scsi_request_fn must get the host_lock before checking + * or modifying starved_list or starved_entry. + */ + sdev = list_entry(shost->starved_list.next, + struct scsi_device, starved_entry); + list_del_init(&sdev->starved_entry); + spin_unlock_irqrestore(shost->host_lock, flags); + + blk_run_queue(sdev->request_queue); + + spin_lock_irqsave(shost->host_lock, flags); + if (unlikely(!list_empty(&sdev->starved_entry))) + /* + * sdev lost a race, and was put back on the + * starved list. This is unlikely but without this + * in theory we could loop forever. + */ + break; + } + spin_unlock_irqrestore(shost->host_lock, flags); + + blk_run_queue(q); +} + +/* + * Function: scsi_requeue_command() + * + * Purpose: Handle post-processing of completed commands. + * + * Arguments: q - queue to operate on + * cmd - command that may need to be requeued. + * + * Returns: Nothing + * + * Notes: After command completion, there may be blocks left + * over which weren't finished by the previous command + * this can be for a number of reasons - the main one is + * I/O errors in the middle of the request, in which case + * we need to request the blocks that come after the bad + * sector. + */ +static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) +{ + cmd->request->flags &= ~REQ_DONTPREP; + blk_insert_request(q, cmd->request, 1, cmd, 1); + + scsi_run_queue(q); +} + +void scsi_next_command(struct scsi_cmnd *cmd) +{ + struct request_queue *q = cmd->device->request_queue; + + scsi_put_command(cmd); + scsi_run_queue(q); +} + +void scsi_run_host_queues(struct Scsi_Host *shost) +{ + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) + scsi_run_queue(sdev->request_queue); +} + +/* + * Function: scsi_end_request() + * + * Purpose: Post-processing of completed commands (usually invoked at end + * of upper level post-processing and scsi_io_completion). + * + * Arguments: cmd - command that is complete. + * uptodate - 1 if I/O indicates success, <= 0 for I/O error. + * bytes - number of bytes of completed I/O + * requeue - indicates whether we should requeue leftovers. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: cmd if requeue done or required, NULL otherwise + * + * 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. + */ +static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, + int bytes, int requeue) +{ + request_queue_t *q = cmd->device->request_queue; + struct request *req = cmd->request; + unsigned long flags; + + /* + * If there are blocks left over at the end, set up the command + * to queue the remainder of them. + */ + if (end_that_request_chunk(req, uptodate, bytes)) { + int leftover = (req->hard_nr_sectors << 9); + + if (blk_pc_request(req)) + leftover = req->data_len; + + /* kill remainder if no retrys */ + if (!uptodate && blk_noretry_request(req)) + end_that_request_chunk(req, 0, leftover); + else { + if (requeue) + /* + * Bleah. Leftovers again. Stick the + * leftovers in the front of the + * queue, and goose the queue again. + */ + scsi_requeue_command(q, cmd); + + return cmd; + } + } + + 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); + + /* + * This will goose the queue request function at the end, so we don't + * need to worry about launching another command. + */ + scsi_next_command(cmd); + return NULL; +} + +static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, int gfp_mask) +{ + struct scsi_host_sg_pool *sgp; + struct scatterlist *sgl; + + BUG_ON(!cmd->use_sg); + + switch (cmd->use_sg) { + case 1 ... 8: + cmd->sglist_len = 0; + break; + case 9 ... 16: + cmd->sglist_len = 1; + break; + case 17 ... 32: + cmd->sglist_len = 2; + break; +#if (SCSI_MAX_PHYS_SEGMENTS > 32) + case 33 ... 64: + cmd->sglist_len = 3; + break; +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + case 65 ... 128: + cmd->sglist_len = 4; + break; +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + case 129 ... 256: + cmd->sglist_len = 5; + break; +#endif +#endif +#endif + default: + return NULL; + } + + sgp = scsi_sg_pools + cmd->sglist_len; + sgl = mempool_alloc(sgp->pool, gfp_mask); + if (sgl) + memset(sgl, 0, sgp->size); + return sgl; +} + +static void scsi_free_sgtable(struct scatterlist *sgl, int index) +{ + struct scsi_host_sg_pool *sgp; + + BUG_ON(index > SG_MEMPOOL_NR); + + sgp = scsi_sg_pools + index; + mempool_free(sgl, sgp->pool); +} + +/* + * Function: scsi_release_buffers() + * + * Purpose: Completion processing for block device I/O requests. + * + * Arguments: cmd - command that we are bailing. + * + * Lock status: Assumed that no lock is held upon entry. + * + * Returns: Nothing + * + * Notes: In the event that an upper level driver rejects a + * command, we must release resources allocated during + * the __init_io() function. Primarily this would involve + * the scatter-gather table, and potentially any bounce + * buffers. + */ +static void scsi_release_buffers(struct scsi_cmnd *cmd) +{ + struct request *req = cmd->request; + + /* + * Free up any indirection buffers we allocated for DMA purposes. + */ + if (cmd->use_sg) + scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + else if (cmd->request_buffer != req->buffer) + kfree(cmd->request_buffer); + + /* + * Zero these out. They now point to freed memory, and it is + * dangerous to hang onto the pointers. + */ + cmd->buffer = NULL; + cmd->bufflen = 0; + cmd->request_buffer = NULL; + cmd->request_bufflen = 0; +} + +/* + * Function: scsi_io_completion() + * + * Purpose: Completion processing for block device I/O requests. + * + * Arguments: cmd - command that is finished. + * + * Lock status: Assumed that no lock is held upon entry. + * + * Returns: Nothing + * + * Notes: This function is matched in terms of capabilities to + * the function that created the scatter-gather list. + * In other words, if there are no bounce buffers + * (the normal case for most drivers), we don't need + * the logic to deal with cleaning up afterwards. + * + * We must do one of several things here: + * + * a) Call scsi_end_request. This will finish off the + * specified number of sectors. If we are done, the + * command block will be released, and the queue + * function will be goosed. If we are not done, then + * scsi_end_request will directly goose the queue. + * + * b) We can just use scsi_requeue_command() here. This would + * be used if we just wanted to retry, for example. + */ +void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, + unsigned int block_bytes) +{ + int result = cmd->result; + int this_count = cmd->bufflen; + request_queue_t *q = cmd->device->request_queue; + struct request *req = cmd->request; + int clear_errors = 1; + struct scsi_sense_hdr sshdr; + int sense_valid = 0; + int sense_deferred = 0; + + if (blk_complete_barrier_rq(q, req, good_bytes >> 9)) + return; + + /* + * Free up any indirection buffers we allocated for DMA purposes. + * For the case of a READ, we need to copy the data out of the + * bounce buffer and into the real buffer. + */ + if (cmd->use_sg) + scsi_free_sgtable(cmd->buffer, cmd->sglist_len); + else if (cmd->buffer != req->buffer) { + if (rq_data_dir(req) == READ) { + unsigned long flags; + char *to = bio_kmap_irq(req->bio, &flags); + memcpy(to, cmd->buffer, cmd->bufflen); + bio_kunmap_irq(to, &flags); + } + kfree(cmd->buffer); + } + + if (result) { + sense_valid = scsi_command_normalize_sense(cmd, &sshdr); + if (sense_valid) + sense_deferred = scsi_sense_is_deferred(&sshdr); + } + if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ + req->errors = result; + if (result) { + clear_errors = 0; + if (sense_valid && req->sense) { + /* + * SG_IO wants current and deferred errors + */ + int len = 8 + cmd->sense_buffer[7]; + + if (len > SCSI_SENSE_BUFFERSIZE) + len = SCSI_SENSE_BUFFERSIZE; + memcpy(req->sense, cmd->sense_buffer, len); + req->sense_len = len; + } + } else + req->data_len = cmd->resid; + } + + /* + * Zero these out. They now point to freed memory, and it is + * dangerous to hang onto the pointers. + */ + cmd->buffer = NULL; + cmd->bufflen = 0; + cmd->request_buffer = NULL; + cmd->request_bufflen = 0; + + /* + * Next deal with any sectors which we were able to correctly + * handle. + */ + if (good_bytes >= 0) { + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n", + req->nr_sectors, good_bytes)); + SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); + + if (clear_errors) + req->errors = 0; + /* + * If multiple sectors are requested in one buffer, then + * they will have been finished off by the first command. + * If not, then we have a multi-buffer command. + * + * If block_bytes != 0, it means we had a medium error + * of some sort, and that we want to mark some number of + * sectors as not uptodate. Thus we want to inhibit + * requeueing right here - we will requeue down below + * when we handle the bad sectors. + */ + cmd = scsi_end_request(cmd, 1, good_bytes, result == 0); + + /* + * If the command completed without error, then either finish off the + * rest of the command, or start a new one. + */ + if (result == 0 || cmd == NULL ) { + return; + } + } + /* + * Now, if we were good little boys and girls, Santa left us a request + * sense buffer. We can extract information from this, so we + * can choose a block to remap, etc. + */ + if (sense_valid && !sense_deferred) { + switch (sshdr.sense_key) { + case UNIT_ATTENTION: + if (cmd->device->removable) { + /* detected disc change. set a bit + * and quietly refuse further access. + */ + cmd->device->changed = 1; + cmd = scsi_end_request(cmd, 0, + this_count, 1); + return; + } else { + /* + * Must have been a power glitch, or a + * bus reset. Could not have been a + * media change, so we just retry the + * request and see what happens. + */ + scsi_requeue_command(q, cmd); + return; + } + break; + case ILLEGAL_REQUEST: + /* + * If we had an ILLEGAL REQUEST returned, then we may + * have performed an unsupported command. The only + * thing this should be would be a ten byte read where + * only a six byte read was supported. Also, on a + * system where READ CAPACITY failed, we may have read + * past the end of the disk. + */ + if (cmd->device->use_10_for_rw && + (cmd->cmnd[0] == READ_10 || + cmd->cmnd[0] == WRITE_10)) { + cmd->device->use_10_for_rw = 0; + /* + * This will cause a retry with a 6-byte + * command. + */ + scsi_requeue_command(q, cmd); + result = 0; + } else { + cmd = scsi_end_request(cmd, 0, this_count, 1); + return; + } + break; + case NOT_READY: + /* + * If the device is in the process of becoming ready, + * retry. + */ + if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { + scsi_requeue_command(q, cmd); + return; + } + printk(KERN_INFO "Device %s not ready.\n", + req->rq_disk ? req->rq_disk->disk_name : ""); + cmd = scsi_end_request(cmd, 0, this_count, 1); + return; + case VOLUME_OVERFLOW: + printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ", + cmd->device->host->host_no, + (int)cmd->device->channel, + (int)cmd->device->id, (int)cmd->device->lun); + __scsi_print_command(cmd->data_cmnd); + scsi_print_sense("", cmd); + cmd = scsi_end_request(cmd, 0, block_bytes, 1); + return; + default: + break; + } + } /* driver byte != 0 */ + if (host_byte(result) == DID_RESET) { + /* + * Third party bus reset or reset for error + * recovery reasons. Just retry the request + * and see what happens. + */ + scsi_requeue_command(q, cmd); + return; + } + if (result) { + printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " + "= 0x%x\n", cmd->device->host->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, result); + + if (driver_byte(result) & DRIVER_SENSE) + scsi_print_sense("", cmd); + /* + * Mark a single buffer as not uptodate. Queue the remainder. + * We sometimes get this cruft in the event that a medium error + * isn't properly reported. + */ + block_bytes = req->hard_cur_sectors << 9; + if (!block_bytes) + block_bytes = req->data_len; + cmd = scsi_end_request(cmd, 0, block_bytes, 1); + } +} +EXPORT_SYMBOL(scsi_io_completion); + +/* + * Function: scsi_init_io() + * + * Purpose: SCSI I/O initialize function. + * + * Arguments: cmd - Command descriptor we wish to initialize + * + * Returns: 0 on success + * BLKPREP_DEFER if the failure is retryable + * BLKPREP_KILL if the failure is fatal + */ +static int scsi_init_io(struct scsi_cmnd *cmd) +{ + struct request *req = cmd->request; + struct scatterlist *sgpnt; + int count; + + /* + * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer + */ + if ((req->flags & REQ_BLOCK_PC) && !req->bio) { + cmd->request_bufflen = req->data_len; + cmd->request_buffer = req->data; + req->buffer = req->data; + cmd->use_sg = 0; + return 0; + } + + /* + * we used to not use scatter-gather for single segment request, + * but now we do (it makes highmem I/O easier to support without + * kmapping pages) + */ + cmd->use_sg = req->nr_phys_segments; + + /* + * if sg table allocation fails, requeue request later. + */ + sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC); + if (unlikely(!sgpnt)) { + req->flags |= REQ_SPECIAL; + return BLKPREP_DEFER; + } + + cmd->request_buffer = (char *) sgpnt; + cmd->request_bufflen = req->nr_sectors << 9; + if (blk_pc_request(req)) + cmd->request_bufflen = req->data_len; + req->buffer = NULL; + + /* + * Next, walk the list, and fill in the addresses and sizes of + * each segment. + */ + count = blk_rq_map_sg(req->q, req, cmd->request_buffer); + + /* + * mapped well, send it off + */ + if (likely(count <= cmd->use_sg)) { + cmd->use_sg = count; + return 0; + } + + printk(KERN_ERR "Incorrect number of segments after building list\n"); + printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg); + printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, + req->current_nr_sectors); + + /* release the command and kill it */ + scsi_release_buffers(cmd); + scsi_put_command(cmd); + return BLKPREP_KILL; +} + +static int scsi_prepare_flush_fn(request_queue_t *q, struct request *rq) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_driver *drv; + + if (sdev->sdev_state == SDEV_RUNNING) { + drv = *(struct scsi_driver **) rq->rq_disk->private_data; + + if (drv->prepare_flush) + return drv->prepare_flush(q, rq); + } + + return 0; +} + +static void scsi_end_flush_fn(request_queue_t *q, struct request *rq) +{ + struct scsi_device *sdev = q->queuedata; + struct request *flush_rq = rq->end_io_data; + struct scsi_driver *drv; + + if (flush_rq->errors) { + printk("scsi: barrier error, disabling flush support\n"); + blk_queue_ordered(q, QUEUE_ORDERED_NONE); + } + + if (sdev->sdev_state == SDEV_RUNNING) { + drv = *(struct scsi_driver **) rq->rq_disk->private_data; + drv->end_flush(q, rq); + } +} + +static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, + sector_t *error_sector) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_driver *drv; + + if (sdev->sdev_state != SDEV_RUNNING) + return -ENXIO; + + drv = *(struct scsi_driver **) disk->private_data; + if (drv->issue_flush) + return drv->issue_flush(&sdev->sdev_gendev, error_sector); + + return -EOPNOTSUPP; +} + +static int scsi_prep_fn(struct request_queue *q, struct request *req) +{ + struct scsi_device *sdev = q->queuedata; + struct scsi_cmnd *cmd; + int specials_only = 0; + + /* + * Just check to see if the device is online. If it isn't, we + * refuse to process any commands. The device must be brought + * online before trying any recovery commands + */ + if (unlikely(!scsi_device_online(sdev))) { + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n", + sdev->host->host_no, sdev->id, sdev->lun); + return BLKPREP_KILL; + } + 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 = sdev->sdev_state; + } + + /* + * Find the actual device driver associated with this command. + * The SPECIAL requests are things like character device or + * ioctls, which did not originate from ll_rw_blk. Note that + * the special field is also used to indicate the cmd for + * the remainder of a partially fulfilled request that can + * come up when there is a medium error. We have to treat + * these two cases differently. We differentiate by looking + * at request->cmd, as this tells us the real story. + */ + if (req->flags & REQ_SPECIAL) { + struct scsi_request *sreq = req->special; + + if (sreq->sr_magic == SCSI_REQ_MAGIC) { + cmd = scsi_get_command(sreq->sr_device, GFP_ATOMIC); + if (unlikely(!cmd)) + goto defer; + scsi_init_cmd_from_req(cmd, sreq); + } else + cmd = req->special; + } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + + if(unlikely(specials_only)) { + if(specials_only == SDEV_QUIESCE || + specials_only == SDEV_BLOCK) + return BLKPREP_DEFER; + + 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; + } + + + /* + * Now try and find a command block that we can use. + */ + if (!req->special) { + cmd = scsi_get_command(sdev, GFP_ATOMIC); + if (unlikely(!cmd)) + goto defer; + } else + cmd = req->special; + + /* pull a tag out of the request if we have one */ + cmd->tag = req->tag; + } else { + blk_dump_rq_flags(req, "SCSI bad req"); + return BLKPREP_KILL; + } + + /* note the overloading of req->special. When the tag + * is active it always means cmd. If the tag goes + * back for re-queueing, it may be reset */ + req->special = cmd; + cmd->request = req; + + /* + * FIXME: drop the lock here because the functions below + * expect to be called without the queue lock held. Also, + * previously, we dequeued the request before dropping the + * lock. We hope REQ_STARTED prevents anything untoward from + * happening now. + */ + if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + struct scsi_driver *drv; + int ret; + + /* + * This will do a couple of things: + * 1) Fill in the actual SCSI command. + * 2) Fill in any other upper-level specific fields + * (timeout). + * + * If this returns 0, it means that the request failed + * (reading past end of disk, reading offline device, + * etc). This won't actually talk to the device, but + * some kinds of consistency checking may cause the + * request to be rejected immediately. + */ + + /* + * This sets up the scatter-gather table (allocating if + * required). + */ + ret = scsi_init_io(cmd); + if (ret) /* BLKPREP_KILL return also releases the command */ + return ret; + + /* + * Initialize the actual SCSI command for this request. + */ + drv = *(struct scsi_driver **)req->rq_disk->private_data; + if (unlikely(!drv->init_command(cmd))) { + scsi_release_buffers(cmd); + scsi_put_command(cmd); + return BLKPREP_KILL; + } + } + + /* + * The request is now prepped, no need to come back here + */ + req->flags |= REQ_DONTPREP; + return BLKPREP_OK; + + defer: + /* If we defer, the elv_next_request() returns NULL, but the + * queue must be restarted, so we plug here if no returning + * command will automatically do that. */ + if (sdev->device_busy == 0) + blk_plug_device(q); + return BLKPREP_DEFER; +} + +/* + * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else + * return 0. + * + * Called with the queue_lock held. + */ +static inline int scsi_dev_queue_ready(struct request_queue *q, + struct scsi_device *sdev) +{ + if (sdev->device_busy >= sdev->queue_depth) + return 0; + if (sdev->device_busy == 0 && sdev->device_blocked) { + /* + * unblock after device_blocked iterates to zero + */ + if (--sdev->device_blocked == 0) { + SCSI_LOG_MLQUEUE(3, + printk("scsi%d (%d:%d) unblocking device at" + " zero depth\n", sdev->host->host_no, + sdev->id, sdev->lun)); + } else { + blk_plug_device(q); + return 0; + } + } + if (sdev->device_blocked) + return 0; + + return 1; +} + +/* + * scsi_host_queue_ready: if we can send requests to shost, return 1 else + * return 0. We must end up running the queue again whenever 0 is + * returned, else IO can hang. + * + * Called with host_lock held. + */ +static inline int scsi_host_queue_ready(struct request_queue *q, + struct Scsi_Host *shost, + struct scsi_device *sdev) +{ + if (test_bit(SHOST_RECOVERY, &shost->shost_state)) + return 0; + if (shost->host_busy == 0 && shost->host_blocked) { + /* + * unblock after host_blocked iterates to zero + */ + if (--shost->host_blocked == 0) { + SCSI_LOG_MLQUEUE(3, + printk("scsi%d unblocking host at zero depth\n", + shost->host_no)); + } else { + blk_plug_device(q); + return 0; + } + } + if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || + shost->host_blocked || shost->host_self_blocked) { + if (list_empty(&sdev->starved_entry)) + list_add_tail(&sdev->starved_entry, &shost->starved_list); + return 0; + } + + /* We're OK to process the command, so we can't be starved */ + if (!list_empty(&sdev->starved_entry)) + list_del_init(&sdev->starved_entry); + + return 1; +} + +/* + * Kill requests for a dead device + */ +static void scsi_kill_requests(request_queue_t *q) +{ + struct request *req; + + while ((req = elv_next_request(q)) != NULL) { + blkdev_dequeue_request(req); + req->flags |= REQ_QUIET; + while (end_that_request_first(req, 0, req->nr_sectors)) + ; + end_that_request_last(req); + } +} + +/* + * Function: scsi_request_fn() + * + * Purpose: Main strategy routine for SCSI. + * + * Arguments: q - Pointer to actual queue. + * + * Returns: Nothing + * + * Lock status: IO request lock assumed to be held when called. + */ +static void scsi_request_fn(struct request_queue *q) +{ + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost; + struct scsi_cmnd *cmd; + struct request *req; + + if (!sdev) { + printk("scsi: killing requests for dead queue\n"); + scsi_kill_requests(q); + return; + } + + 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. + */ + shost = sdev->host; + while (!blk_queue_plugged(q)) { + int rtn; + /* + * get next queueable request. We do this early to make sure + * that the request is fully prepared even if we cannot + * accept it. + */ + req = elv_next_request(q); + if (!req || !scsi_dev_queue_ready(q, sdev)) + break; + + if (unlikely(!scsi_device_online(sdev))) { + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n", + sdev->host->host_no, sdev->id, sdev->lun); + blkdev_dequeue_request(req); + req->flags |= REQ_QUIET; + while (end_that_request_first(req, 0, req->nr_sectors)) + ; + end_that_request_last(req); + continue; + } + + + /* + * Remove the request from the request list. + */ + if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req))) + blkdev_dequeue_request(req); + sdev->device_busy++; + + spin_unlock(q->queue_lock); + spin_lock(shost->host_lock); + + if (!scsi_host_queue_ready(q, shost, sdev)) + goto not_ready; + if (sdev->single_lun) { + if (scsi_target(sdev)->starget_sdev_user && + scsi_target(sdev)->starget_sdev_user != sdev) + goto not_ready; + scsi_target(sdev)->starget_sdev_user = sdev; + } + shost->host_busy++; + + /* + * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will + * take the lock again. + */ + spin_unlock_irq(shost->host_lock); + + cmd = req->special; + if (unlikely(cmd == NULL)) { + printk(KERN_CRIT "impossible request in %s.\n" + "please mail a stack trace to " + "linux-scsi@vger.kernel.org", + __FUNCTION__); + BUG(); + } + + /* + * Finally, initialize any error handling parameters, and set up + * the timers for timeouts. + */ + scsi_init_cmd_errh(cmd); + + /* + * Dispatch the command to the low-level driver. + */ + rtn = scsi_dispatch_cmd(cmd); + spin_lock_irq(q->queue_lock); + if(rtn) { + /* we're refusing the command; because of + * the way locks get dropped, we need to + * check here if plugging is required */ + if(sdev->device_busy == 0) + blk_plug_device(q); + + break; + } + } + + goto out; + + not_ready: + spin_unlock_irq(shost->host_lock); + + /* + * lock q, handle tag, requeue req, and decrement device_busy. We + * must return with queue_lock held. + * + * Decrementing device_busy without checking it is OK, as all such + * cases (host limits or settings) should run the queue at some + * later time. + */ + spin_lock_irq(q->queue_lock); + blk_requeue_request(q, req); + 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) +{ + struct device *host_dev; + u64 bounce_limit = 0xffffffff; + + if (shost->unchecked_isa_dma) + return BLK_BOUNCE_ISA; + /* + * Platforms with virtual-DMA translation + * hardware have no practical limit. + */ + if (!PCI_DMA_BUS_IS_PHYS) + return BLK_BOUNCE_ANY; + + host_dev = scsi_get_device(shost); + if (host_dev && host_dev->dma_mask) + bounce_limit = *host_dev->dma_mask; + + return bounce_limit; +} +EXPORT_SYMBOL(scsi_calculate_bounce_limit); + +struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = sdev->host; + struct request_queue *q; + + q = blk_init_queue(scsi_request_fn, &sdev->sdev_lock); + if (!q) + return NULL; + + blk_queue_prep_rq(q, scsi_prep_fn); + + blk_queue_max_hw_segments(q, shost->sg_tablesize); + blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); + blk_queue_max_sectors(q, shost->max_sectors); + blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); + blk_queue_segment_boundary(q, shost->dma_boundary); + blk_queue_issue_flush_fn(q, scsi_issue_flush_fn); + + /* + * ordered tags are superior to flush ordering + */ + if (shost->ordered_tag) + blk_queue_ordered(q, QUEUE_ORDERED_TAG); + else if (shost->ordered_flush) { + blk_queue_ordered(q, QUEUE_ORDERED_FLUSH); + q->prepare_flush_fn = scsi_prepare_flush_fn; + q->end_flush_fn = scsi_end_flush_fn; + } + + if (!shost->use_clustering) + clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + return q; +} + +void scsi_free_queue(struct request_queue *q) +{ + blk_cleanup_queue(q); +} + +/* + * Function: scsi_block_requests() + * + * Purpose: Utility function used by low-level drivers to prevent further + * commands from being queued to the device. + * + * Arguments: shost - Host in question + * + * Returns: Nothing + * + * Lock status: No locks are assumed held. + * + * Notes: There is no timer nor any other means by which the requests + * get unblocked other than the low-level driver calling + * scsi_unblock_requests(). + */ +void scsi_block_requests(struct Scsi_Host *shost) +{ + shost->host_self_blocked = 1; +} +EXPORT_SYMBOL(scsi_block_requests); + +/* + * Function: scsi_unblock_requests() + * + * Purpose: Utility function used by low-level drivers to allow further + * commands from being queued to the device. + * + * Arguments: shost - Host in question + * + * Returns: Nothing + * + * Lock status: No locks are assumed held. + * + * Notes: There is no timer nor any other means by which the requests + * get unblocked other than the low-level driver calling + * scsi_unblock_requests(). + * + * This is done as an API function so that changes to the + * internals of the scsi mid-layer won't require wholesale + * changes to drivers that use this feature. + */ +void scsi_unblock_requests(struct Scsi_Host *shost) +{ + shost->host_self_blocked = 0; + scsi_run_host_queues(shost); +} +EXPORT_SYMBOL(scsi_unblock_requests); + +int __init scsi_init_queue(void) +{ + int i; + + for (i = 0; i < SG_MEMPOOL_NR; i++) { + struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; + int size = sgp->size * sizeof(struct scatterlist); + + sgp->slab = kmem_cache_create(sgp->name, size, 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!sgp->slab) { + printk(KERN_ERR "SCSI: can't init sg slab %s\n", + sgp->name); + } + + sgp->pool = mempool_create(SG_MEMPOOL_SIZE, + mempool_alloc_slab, mempool_free_slab, + sgp->slab); + if (!sgp->pool) { + printk(KERN_ERR "SCSI: can't init sg mempool %s\n", + sgp->name); + } + } + + return 0; +} + +void scsi_exit_queue(void) +{ + int i; + + for (i = 0; i < SG_MEMPOOL_NR; i++) { + struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; + mempool_destroy(sgp->pool); + kmem_cache_destroy(sgp->slab); + } +} +/** + * __scsi_mode_sense - issue a mode sense, falling back from 10 to + * six bytes if necessary. + * @sreq: SCSI request to fill in with the MODE_SENSE + * @dbd: set if mode sense will allow block descriptors to be returned + * @modepage: mode page being requested + * @buffer: request buffer (may not be smaller than eight bytes) + * @len: length of request buffer. + * @timeout: command timeout + * @retries: number of retries before failing + * @data: returns a structure abstracting the mode header data + * + * Returns zero if unsuccessful, or the header offset (either 4 + * or 8 depending on whether a six or ten byte command was + * issued) if successful. + **/ +int +__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, + unsigned char *buffer, int len, int timeout, int retries, + struct scsi_mode_data *data) { + unsigned char cmd[12]; + int use_10_for_ms; + int header_length; + + memset(data, 0, sizeof(*data)); + memset(&cmd[0], 0, 12); + cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ + cmd[2] = modepage; + + retry: + use_10_for_ms = sreq->sr_device->use_10_for_ms; + + if (use_10_for_ms) { + if (len < 8) + len = 8; + + cmd[0] = MODE_SENSE_10; + cmd[8] = len; + header_length = 8; + } else { + if (len < 4) + len = 4; + + cmd[0] = MODE_SENSE; + cmd[4] = len; + header_length = 4; + } + + sreq->sr_cmd_len = 0; + memset(sreq->sr_sense_buffer, 0, sizeof(sreq->sr_sense_buffer)); + sreq->sr_data_direction = DMA_FROM_DEVICE; + + memset(buffer, 0, len); + + scsi_wait_req(sreq, cmd, buffer, len, timeout, retries); + + /* This code looks awful: what it's doing is making sure an + * ILLEGAL REQUEST sense return identifies the actual command + * byte as the problem. MODE_SENSE commands can return + * ILLEGAL REQUEST if the code page isn't supported */ + + if (use_10_for_ms && !scsi_status_is_good(sreq->sr_result) && + (driver_byte(sreq->sr_result) & DRIVER_SENSE)) { + struct scsi_sense_hdr sshdr; + + if (scsi_request_normalize_sense(sreq, &sshdr)) { + if ((sshdr.sense_key == ILLEGAL_REQUEST) && + (sshdr.asc == 0x20) && (sshdr.ascq == 0)) { + /* + * Invalid command operation code + */ + sreq->sr_device->use_10_for_ms = 0; + goto retry; + } + } + } + + if(scsi_status_is_good(sreq->sr_result)) { + data->header_length = header_length; + if(use_10_for_ms) { + data->length = buffer[0]*256 + buffer[1] + 2; + data->medium_type = buffer[2]; + data->device_specific = buffer[3]; + data->longlba = buffer[4] & 0x01; + data->block_descriptor_length = buffer[6]*256 + + buffer[7]; + } else { + data->length = buffer[0] + 1; + data->medium_type = buffer[1]; + data->device_specific = buffer[2]; + data->block_descriptor_length = buffer[3]; + } + } + + return sreq->sr_result; +} +EXPORT_SYMBOL(__scsi_mode_sense); + +/** + * scsi_mode_sense - issue a mode sense, falling back from 10 to + * six bytes if necessary. + * @sdev: scsi device to send command to. + * @dbd: set if mode sense will disable block descriptors in the return + * @modepage: mode page being requested + * @buffer: request buffer (may not be smaller than eight bytes) + * @len: length of request buffer. + * @timeout: command timeout + * @retries: number of retries before failing + * + * Returns zero if unsuccessful, or the header offset (either 4 + * or 8 depending on whether a six or ten byte command was + * issued) if successful. + **/ +int +scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, + unsigned char *buffer, int len, int timeout, int retries, + struct scsi_mode_data *data) +{ + struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); + int ret; + + if (!sreq) + return -1; + + ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len, + timeout, retries, data); + + scsi_release_request(sreq); + + return ret; +} +EXPORT_SYMBOL(scsi_mode_sense); + +int +scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) +{ + struct scsi_request *sreq; + char cmd[] = { + TEST_UNIT_READY, 0, 0, 0, 0, 0, + }; + int result; + + sreq = scsi_allocate_request(sdev, GFP_KERNEL); + if (!sreq) + return -ENOMEM; + + sreq->sr_data_direction = DMA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + + if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) { + struct scsi_sense_hdr sshdr; + + if ((scsi_request_normalize_sense(sreq, &sshdr)) && + ((sshdr.sense_key == UNIT_ATTENTION) || + (sshdr.sense_key == NOT_READY))) { + sdev->changed = 1; + sreq->sr_result = 0; + } + } + result = sreq->sr_result; + scsi_release_request(sreq); + return result; +} +EXPORT_SYMBOL(scsi_test_unit_ready); + +/** + * scsi_device_set_state - Take the given device through the device + * state model. + * @sdev: scsi device to change the state of. + * @state: state to change to. + * + * Returns zero if unsuccessful or an error if the requested + * transition is illegal. + **/ +int +scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) +{ + enum scsi_device_state oldstate = sdev->sdev_state; + + if (state == oldstate) + return 0; + + switch (state) { + case SDEV_CREATED: + /* There are no legal states that come back to + * created. This is the manually initialised start + * state */ + goto illegal; + + case SDEV_RUNNING: + switch (oldstate) { + case SDEV_CREATED: + case SDEV_OFFLINE: + case SDEV_QUIESCE: + case SDEV_BLOCK: + break; + default: + goto illegal; + } + break; + + case SDEV_QUIESCE: + switch (oldstate) { + case SDEV_RUNNING: + case SDEV_OFFLINE: + break; + default: + goto illegal; + } + break; + + case SDEV_OFFLINE: + switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + case SDEV_QUIESCE: + case SDEV_BLOCK: + break; + default: + goto illegal; + } + break; + + case SDEV_BLOCK: + switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + break; + default: + goto illegal; + } + break; + + case SDEV_CANCEL: + switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + case SDEV_OFFLINE: + case SDEV_BLOCK: + break; + default: + goto illegal; + } + break; + + case SDEV_DEL: + switch (oldstate) { + case SDEV_CANCEL: + break; + default: + goto illegal; + } + break; + + } + sdev->sdev_state = state; + return 0; + + illegal: + SCSI_LOG_ERROR_RECOVERY(1, + dev_printk(KERN_ERR, &sdev->sdev_gendev, + "Illegal state transition %s->%s\n", + scsi_device_state_name(oldstate), + scsi_device_state_name(state)) + ); + return -EINVAL; +} +EXPORT_SYMBOL(scsi_device_set_state); + +/** + * scsi_device_quiesce - Block user issued commands. + * @sdev: scsi device to quiesce. + * + * This works by trying to transition to the SDEV_QUIESCE state + * (which must be a legal transition). When the device is in this + * state, only special requests will be accepted, all others will + * be deferred. Since special requests may also be requeued requests, + * a successful return doesn't guarantee the device will be + * totally quiescent. + * + * Must be called with user context, may sleep. + * + * Returns zero if unsuccessful or an error if not. + **/ +int +scsi_device_quiesce(struct scsi_device *sdev) +{ + int err = scsi_device_set_state(sdev, SDEV_QUIESCE); + if (err) + return err; + + scsi_run_queue(sdev->request_queue); + while (sdev->device_busy) { + msleep_interruptible(200); + scsi_run_queue(sdev->request_queue); + } + return 0; +} +EXPORT_SYMBOL(scsi_device_quiesce); + +/** + * scsi_device_resume - Restart user issued commands to a quiesced device. + * @sdev: scsi device to resume. + * + * Moves the device from quiesced back to running and restarts the + * queues. + * + * Must be called with user context, may sleep. + **/ +void +scsi_device_resume(struct scsi_device *sdev) +{ + if(scsi_device_set_state(sdev, SDEV_RUNNING)) + return; + scsi_run_queue(sdev->request_queue); +} +EXPORT_SYMBOL(scsi_device_resume); + +static void +device_quiesce_fn(struct scsi_device *sdev, void *data) +{ + scsi_device_quiesce(sdev); +} + +void +scsi_target_quiesce(struct scsi_target *starget) +{ + starget_for_each_device(starget, NULL, device_quiesce_fn); +} +EXPORT_SYMBOL(scsi_target_quiesce); + +static void +device_resume_fn(struct scsi_device *sdev, void *data) +{ + scsi_device_resume(sdev); +} + +void +scsi_target_resume(struct scsi_target *starget) +{ + starget_for_each_device(starget, NULL, device_resume_fn); +} +EXPORT_SYMBOL(scsi_target_resume); + +/** + * scsi_internal_device_block - internal function to put a device + * temporarily into the SDEV_BLOCK state + * @sdev: device to block + * + * Block request made by scsi lld's to temporarily stop all + * scsi commands on the specified device. Called from interrupt + * or normal process context. + * + * Returns zero if successful or error if not + * + * Notes: + * This routine transitions the device to the SDEV_BLOCK state + * (which must be a legal transition). When the device is in this + * state, all commands are deferred until the scsi lld reenables + * the device with scsi_device_unblock or device_block_tmo fires. + * This routine assumes the host_lock is held on entry. + **/ +int +scsi_internal_device_block(struct scsi_device *sdev) +{ + request_queue_t *q = sdev->request_queue; + unsigned long flags; + int err = 0; + + err = scsi_device_set_state(sdev, SDEV_BLOCK); + if (err) + return err; + + /* + * The device has transitioned to SDEV_BLOCK. Stop the + * block layer from calling the midlayer with this device's + * request queue. + */ + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(scsi_internal_device_block); + +/** + * scsi_internal_device_unblock - resume a device after a block request + * @sdev: device to resume + * + * Called by scsi lld's or the midlayer to restart the device queue + * for the previously suspended scsi device. Called from interrupt or + * normal process context. + * + * Returns zero if successful or error if not. + * + * Notes: + * This routine transitions the device to the SDEV_RUNNING state + * (which must be a legal transition) allowing the midlayer to + * goose the queue for this device. This routine assumes the + * host_lock is held upon entry. + **/ +int +scsi_internal_device_unblock(struct scsi_device *sdev) +{ + request_queue_t *q = sdev->request_queue; + int err; + unsigned long flags; + + /* + * Try to transition the scsi device to SDEV_RUNNING + * and goose the device queue if successful. + */ + err = scsi_device_set_state(sdev, SDEV_RUNNING); + if (err) + return err; + + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(scsi_internal_device_unblock); + +static void +device_block(struct scsi_device *sdev, void *data) +{ + scsi_internal_device_block(sdev); +} + +static int +target_block(struct device *dev, void *data) +{ + if (scsi_is_target_device(dev)) + starget_for_each_device(to_scsi_target(dev), NULL, + device_block); + return 0; +} + +void +scsi_target_block(struct device *dev) +{ + if (scsi_is_target_device(dev)) + starget_for_each_device(to_scsi_target(dev), NULL, + device_block); + else + device_for_each_child(dev, NULL, target_block); +} +EXPORT_SYMBOL_GPL(scsi_target_block); + +static void +device_unblock(struct scsi_device *sdev, void *data) +{ + scsi_internal_device_unblock(sdev); +} + +static int +target_unblock(struct device *dev, void *data) +{ + if (scsi_is_target_device(dev)) + starget_for_each_device(to_scsi_target(dev), NULL, + device_unblock); + return 0; +} + +void +scsi_target_unblock(struct device *dev) +{ + if (scsi_is_target_device(dev)) + starget_for_each_device(to_scsi_target(dev), NULL, + device_unblock); + else + device_for_each_child(dev, NULL, target_unblock); +} +EXPORT_SYMBOL_GPL(scsi_target_unblock); |