]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/scsi_lib.c
[SCSI] don't use __GFP_DMA for sense buffers if not required
[~andy/linux] / drivers / scsi / scsi_lib.c
index 207f1aa08869f209be7ba1bde8f727534796701b..4cf902efbdbf14aa26422226491463aa05a2f7cc 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/hardirq.h>
+#include <linux/scatterlist.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #define SG_MEMPOOL_NR          ARRAY_SIZE(scsi_sg_pools)
 #define SG_MEMPOOL_SIZE                2
 
+/*
+ * The maximum number of SG segments that we will put inside a scatterlist
+ * (unless chaining is used). Should ideally fit inside a single page, to
+ * avoid a higher order allocation.
+ */
+#define SCSI_MAX_SG_SEGMENTS   128
+
 struct scsi_host_sg_pool {
        size_t          size;
-       char            *name; 
+       char            *name;
        struct kmem_cache       *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 } 
+#define SP(x) { x, "sgpool-" #x }
 static struct scsi_host_sg_pool scsi_sg_pools[] = {
        SP(8),
        SP(16),
+#if (SCSI_MAX_SG_SEGMENTS > 16)
        SP(32),
-#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+#if (SCSI_MAX_SG_SEGMENTS > 32)
        SP(64),
-#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+#if (SCSI_MAX_SG_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
 
 static void scsi_run_queue(struct request_queue *q);
@@ -175,7 +175,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  *
  * returns the req->errors value which is the scsi_cmnd result
  * field.
- **/
+ */
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
                 unsigned char *sense, int timeout, int retries, int flags)
@@ -274,7 +274,7 @@ static void scsi_bi_endio(struct bio *bio, int error)
 /**
  * scsi_req_map_sg - map a scatterlist into a request
  * @rq:                request to fill
- * @sg:                scatterlist
+ * @sgl:       scatterlist
  * @nsegs:     number of elements
  * @bufflen:   len of buffer
  * @gfp:       memory allocation flags
@@ -289,14 +289,16 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
        struct request_queue *q = rq->q;
        int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
        unsigned int data_len = bufflen, len, bytes, off;
+       struct scatterlist *sg;
        struct page *page;
        struct bio *bio = NULL;
        int i, err, nr_vecs = 0;
 
-       for (i = 0; i < nsegs; i++) {
-               page = sgl[i].page;
-               off = sgl[i].offset;
-               len = sgl[i].length;
+       for_each_sg(sgl, sg, nsegs, i) {
+               page = sg_page(sg);
+               off = sg->offset;
+               len = sg->length;
+               data_len += len;
 
                while (len > 0 && data_len > 0) {
                        /*
@@ -363,14 +365,16 @@ free_bios:
  * @sdev:      scsi device
  * @cmd:       scsi command
  * @cmd_len:   length of scsi cdb
- * @data_direction: data direction
+ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
  * @buffer:    data buffer (this can be a kernel buffer or scatterlist)
  * @bufflen:   len of buffer
  * @use_sg:    if buffer is a scatterlist this is the number of elements
  * @timeout:   request timeout in seconds
  * @retries:   number of times to retry request
- * @flags:     or into request flags
- **/
+ * @privdata:  data passed to done()
+ * @done:      callback function when done
+ * @gfp:       memory allocation flags
+ */
 int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
                       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
                       int use_sg, int timeout, int retries, void *privdata,
@@ -437,7 +441,7 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
        cmd->serial_number = 0;
        cmd->resid = 0;
-       memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+       memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
        if (cmd->cmd_len == 0)
                cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
 }
@@ -522,7 +526,7 @@ static void scsi_run_queue(struct request_queue *q)
        struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
 
-       if (sdev->single_lun)
+       if (scsi_target(sdev)->single_lun)
                scsi_single_lun_run(sdev);
 
        spin_lock_irqsave(shost->host_lock, flags);
@@ -695,56 +699,177 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
        return NULL;
 }
 
-struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
-{
-       struct scsi_host_sg_pool *sgp;
-       struct scatterlist *sgl;
+/*
+ * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit
+ * is totally arbitrary, a setting of 2048 will get you at least 8mb ios.
+ */
+#define SCSI_MAX_SG_CHAIN_SEGMENTS     2048
 
-       BUG_ON(!cmd->use_sg);
+static inline unsigned int scsi_sgtable_index(unsigned short nents)
+{
+       unsigned int index;
 
-       switch (cmd->use_sg) {
+       switch (nents) {
        case 1 ... 8:
-               cmd->sglist_len = 0;
+               index = 0;
                break;
        case 9 ... 16:
-               cmd->sglist_len = 1;
+               index = 1;
                break;
+#if (SCSI_MAX_SG_SEGMENTS > 16)
        case 17 ... 32:
-               cmd->sglist_len = 2;
+               index = 2;
                break;
-#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+#if (SCSI_MAX_SG_SEGMENTS > 32)
        case 33 ... 64:
-               cmd->sglist_len = 3;
+               index = 3;
                break;
-#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+#if (SCSI_MAX_SG_SEGMENTS > 64)
        case 65 ... 128:
-               cmd->sglist_len = 4;
-               break;
-#if (SCSI_MAX_PHYS_SEGMENTS  > 128)
-       case 129 ... 256:
-               cmd->sglist_len = 5;
+               index = 4;
                break;
 #endif
 #endif
 #endif
        default:
-               return NULL;
+               printk(KERN_ERR "scsi: bad segment count=%d\n", nents);
+               BUG();
        }
 
-       sgp = scsi_sg_pools + cmd->sglist_len;
-       sgl = mempool_alloc(sgp->pool, gfp_mask);
-       return sgl;
+       return index;
+}
+
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+       struct scsi_host_sg_pool *sgp;
+       struct scatterlist *sgl, *prev, *ret;
+       unsigned int index;
+       int this, left;
+
+       BUG_ON(!cmd->use_sg);
+
+       left = cmd->use_sg;
+       ret = prev = NULL;
+       do {
+               this = left;
+               if (this > SCSI_MAX_SG_SEGMENTS) {
+                       this = SCSI_MAX_SG_SEGMENTS - 1;
+                       index = SG_MEMPOOL_NR - 1;
+               } else
+                       index = scsi_sgtable_index(this);
+
+               left -= this;
+
+               sgp = scsi_sg_pools + index;
+
+               sgl = mempool_alloc(sgp->pool, gfp_mask);
+               if (unlikely(!sgl))
+                       goto enomem;
+
+               sg_init_table(sgl, sgp->size);
+
+               /*
+                * first loop through, set initial index and return value
+                */
+               if (!ret)
+                       ret = sgl;
+
+               /*
+                * chain previous sglist, if any. we know the previous
+                * sglist must be the biggest one, or we would not have
+                * ended up doing another loop.
+                */
+               if (prev)
+                       sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl);
+
+               /*
+                * if we have nothing left, mark the last segment as
+                * end-of-list
+                */
+               if (!left)
+                       sg_mark_end(&sgl[this - 1]);
+
+               /*
+                * don't allow subsequent mempool allocs to sleep, it would
+                * violate the mempool principle.
+                */
+               gfp_mask &= ~__GFP_WAIT;
+               gfp_mask |= __GFP_HIGH;
+               prev = sgl;
+       } while (left);
+
+       /*
+        * ->use_sg may get modified after dma mapping has potentially
+        * shrunk the number of segments, so keep a copy of it for free.
+        */
+       cmd->__use_sg = cmd->use_sg;
+       return ret;
+enomem:
+       if (ret) {
+               /*
+                * Free entries chained off ret. Since we were trying to
+                * allocate another sglist, we know that all entries are of
+                * the max size.
+                */
+               sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+               prev = ret;
+               ret = &ret[SCSI_MAX_SG_SEGMENTS - 1];
+
+               while ((sgl = sg_chain_ptr(ret)) != NULL) {
+                       ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1];
+                       mempool_free(sgl, sgp->pool);
+               }
+
+               mempool_free(prev, sgp->pool);
+       }
+       return NULL;
 }
 
 EXPORT_SYMBOL(scsi_alloc_sgtable);
 
-void scsi_free_sgtable(struct scatterlist *sgl, int index)
+void scsi_free_sgtable(struct scsi_cmnd *cmd)
 {
+       struct scatterlist *sgl = cmd->request_buffer;
        struct scsi_host_sg_pool *sgp;
 
-       BUG_ON(index >= SG_MEMPOOL_NR);
+       /*
+        * if this is the biggest size sglist, check if we have
+        * chained parts we need to free
+        */
+       if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) {
+               unsigned short this, left;
+               struct scatterlist *next;
+               unsigned int index;
+
+               left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1);
+               next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]);
+               while (left && next) {
+                       sgl = next;
+                       this = left;
+                       if (this > SCSI_MAX_SG_SEGMENTS) {
+                               this = SCSI_MAX_SG_SEGMENTS - 1;
+                               index = SG_MEMPOOL_NR - 1;
+                       } else
+                               index = scsi_sgtable_index(this);
+
+                       left -= this;
+
+                       sgp = scsi_sg_pools + index;
+
+                       if (left)
+                               next = sg_chain_ptr(&sgl[sgp->size - 1]);
+
+                       mempool_free(sgl, sgp->pool);
+               }
+
+               /*
+                * Restore original, will be freed below
+                */
+               sgl = cmd->request_buffer;
+               sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+       } else
+               sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg);
 
-       sgp = scsi_sg_pools + index;
        mempool_free(sgl, sgp->pool);
 }
 
@@ -770,7 +895,7 @@ EXPORT_SYMBOL(scsi_free_sgtable);
 static void scsi_release_buffers(struct scsi_cmnd *cmd)
 {
        if (cmd->use_sg)
-               scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+               scsi_free_sgtable(cmd);
 
        /*
         * Zero these out.  They now point to freed memory, and it is
@@ -979,12 +1104,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
  *
  * 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;
 
        /*
@@ -997,14 +1120,13 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
        /*
         * If sg table allocation fails, requeue request later.
         */
-       sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
-       if (unlikely(!sgpnt)) {
+       cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
+       if (unlikely(!cmd->request_buffer)) {
                scsi_unprep_request(req);
                return BLKPREP_DEFER;
        }
 
        req->buffer = NULL;
-       cmd->request_buffer = (char *) sgpnt;
        if (blk_pc_request(req))
                cmd->request_bufflen = req->data_len;
        else
@@ -1015,17 +1137,9 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
         * each segment.
         */
        count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-       if (likely(count <= cmd->use_sg)) {
-               cmd->use_sg = count;
-               return BLKPREP_OK;
-       }
-
-       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);
-
-       return BLKPREP_KILL;
+       BUG_ON(count > cmd->use_sg);
+       cmd->use_sg = count;
+       return BLKPREP_OK;
 }
 
 static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
@@ -1211,7 +1325,7 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
 }
 EXPORT_SYMBOL(scsi_prep_return);
 
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
        struct scsi_device *sdev = q->queuedata;
        int ret = BLKPREP_KILL;
@@ -1436,7 +1550,7 @@ static void scsi_request_fn(struct request_queue *q)
 
                if (!scsi_host_queue_ready(q, shost, sdev))
                        goto not_ready;
-               if (sdev->single_lun) {
+               if (scsi_target(sdev)->single_lun) {
                        if (scsi_target(sdev)->starget_sdev_user &&
                            scsi_target(sdev)->starget_sdev_user != sdev)
                                goto not_ready;
@@ -1529,14 +1643,39 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
        if (!q)
                return NULL;
 
+       /*
+        * this limit is imposed by hardware restrictions
+        */
        blk_queue_max_hw_segments(q, shost->sg_tablesize);
-       blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
+
+       /*
+        * In the future, sg chaining support will be mandatory and this
+        * ifdef can then go away. Right now we don't have all archs
+        * converted, so better keep it safe.
+        */
+#ifdef ARCH_HAS_SG_CHAIN
+       if (shost->use_sg_chaining)
+               blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+       else
+               blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
+#else
+       blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
+#endif
+
        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);
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+
+       /*
+        * set a reasonable default alignment on word boundaries: the
+        * host and device may alter it using
+        * blk_queue_update_dma_alignment() later.
+        */
+       blk_queue_dma_alignment(q, 0x03);
+
        return q;
 }
 EXPORT_SYMBOL(__scsi_alloc_queue);
@@ -1666,7 +1805,7 @@ void scsi_exit_queue(void)
  *     @timeout: command timeout
  *     @retries: number of retries before failing
  *     @data: returns a structure abstracting the mode header data
- *     @sense: place to put sense data (or NULL if no sense to be collected).
+ *     @sshdr: place to put sense data (or NULL if no sense to be collected).
  *             must be SCSI_SENSE_BUFFERSIZE big.
  *
  *     Returns zero if successful; negative error number or scsi
@@ -1733,8 +1872,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
 EXPORT_SYMBOL_GPL(scsi_mode_select);
 
 /**
- *     scsi_mode_sense - issue a mode sense, falling back from 10 to 
- *             six bytes if necessary.
+ *     scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
  *     @sdev:  SCSI device to be queried
  *     @dbd:   set if mode sense will allow block descriptors to be returned
  *     @modepage: mode page being requested
@@ -1743,13 +1881,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
  *     @timeout: command timeout
  *     @retries: number of retries before failing
  *     @data: returns a structure abstracting the mode header data
- *     @sense: place to put sense data (or NULL if no sense to be collected).
+ *     @sshdr: place to put sense data (or NULL if no sense to be collected).
  *             must be SCSI_SENSE_BUFFERSIZE big.
  *
  *     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,
@@ -1843,40 +1981,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 }
 EXPORT_SYMBOL(scsi_mode_sense);
 
+/**
+ *     scsi_test_unit_ready - test if unit is ready
+ *     @sdev:  scsi device to change the state of.
+ *     @timeout: command timeout
+ *     @retries: number of retries before failing
+ *     @sshdr_external: Optional pointer to struct scsi_sense_hdr for
+ *             returning sense. Make sure that this is cleared before passing
+ *             in.
+ *
+ *     Returns zero if unsuccessful or an error if TUR failed.  For
+ *     removable media, a return of NOT_READY or UNIT_ATTENTION is
+ *     translated to success, with the ->changed flag updated.
+ **/
 int
-scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
+                    struct scsi_sense_hdr *sshdr_external)
 {
        char cmd[] = {
                TEST_UNIT_READY, 0, 0, 0, 0, 0,
        };
-       struct scsi_sense_hdr sshdr;
+       struct scsi_sense_hdr *sshdr;
        int result;
-       
-       result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
-                                 timeout, retries);
+
+       if (!sshdr_external)
+               sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+       else
+               sshdr = sshdr_external;
+
+       /* try to eat the UNIT_ATTENTION if there are enough retries */
+       do {
+               result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
+                                         timeout, retries);
+       } while ((driver_byte(result) & DRIVER_SENSE) &&
+                sshdr && sshdr->sense_key == UNIT_ATTENTION &&
+                --retries);
+
+       if (!sshdr)
+               /* could not allocate sense buffer, so can't process it */
+               return result;
 
        if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
 
-               if ((scsi_sense_valid(&sshdr)) &&
-                   ((sshdr.sense_key == UNIT_ATTENTION) ||
-                    (sshdr.sense_key == NOT_READY))) {
+               if ((scsi_sense_valid(sshdr)) &&
+                   ((sshdr->sense_key == UNIT_ATTENTION) ||
+                    (sshdr->sense_key == NOT_READY))) {
                        sdev->changed = 1;
                        result = 0;
                }
        }
+       if (!sshdr_external)
+               kfree(sshdr);
        return result;
 }
 EXPORT_SYMBOL(scsi_test_unit_ready);
 
 /**
- *     scsi_device_set_state - Take the given device through the device
- *             state model.
+ *     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)
 {
@@ -1976,6 +2143,142 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 }
 EXPORT_SYMBOL(scsi_device_set_state);
 
+/**
+ *     sdev_evt_emit - emit a single SCSI device uevent
+ *     @sdev: associated SCSI device
+ *     @evt: event to emit
+ *
+ *     Send a single uevent (scsi_event) to the associated scsi_device.
+ */
+static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
+{
+       int idx = 0;
+       char *envp[3];
+
+       switch (evt->evt_type) {
+       case SDEV_EVT_MEDIA_CHANGE:
+               envp[idx++] = "SDEV_MEDIA_CHANGE=1";
+               break;
+
+       default:
+               /* do nothing */
+               break;
+       }
+
+       envp[idx++] = NULL;
+
+       kobject_uevent_env(&sdev->sdev_gendev.kobj, KOBJ_CHANGE, envp);
+}
+
+/**
+ *     sdev_evt_thread - send a uevent for each scsi event
+ *     @work: work struct for scsi_device
+ *
+ *     Dispatch queued events to their associated scsi_device kobjects
+ *     as uevents.
+ */
+void scsi_evt_thread(struct work_struct *work)
+{
+       struct scsi_device *sdev;
+       LIST_HEAD(event_list);
+
+       sdev = container_of(work, struct scsi_device, event_work);
+
+       while (1) {
+               struct scsi_event *evt;
+               struct list_head *this, *tmp;
+               unsigned long flags;
+
+               spin_lock_irqsave(&sdev->list_lock, flags);
+               list_splice_init(&sdev->event_list, &event_list);
+               spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+               if (list_empty(&event_list))
+                       break;
+
+               list_for_each_safe(this, tmp, &event_list) {
+                       evt = list_entry(this, struct scsi_event, node);
+                       list_del(&evt->node);
+                       scsi_evt_emit(sdev, evt);
+                       kfree(evt);
+               }
+       }
+}
+
+/**
+ *     sdev_evt_send - send asserted event to uevent thread
+ *     @sdev: scsi_device event occurred on
+ *     @evt: event to send
+ *
+ *     Assert scsi device event asynchronously.
+ */
+void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt)
+{
+       unsigned long flags;
+
+       if (!test_bit(evt->evt_type, sdev->supported_events)) {
+               kfree(evt);
+               return;
+       }
+
+       spin_lock_irqsave(&sdev->list_lock, flags);
+       list_add_tail(&evt->node, &sdev->event_list);
+       schedule_work(&sdev->event_work);
+       spin_unlock_irqrestore(&sdev->list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdev_evt_send);
+
+/**
+ *     sdev_evt_alloc - allocate a new scsi event
+ *     @evt_type: type of event to allocate
+ *     @gfpflags: GFP flags for allocation
+ *
+ *     Allocates and returns a new scsi_event.
+ */
+struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
+                                 gfp_t gfpflags)
+{
+       struct scsi_event *evt = kzalloc(sizeof(struct scsi_event), gfpflags);
+       if (!evt)
+               return NULL;
+
+       evt->evt_type = evt_type;
+       INIT_LIST_HEAD(&evt->node);
+
+       /* evt_type-specific initialization, if any */
+       switch (evt_type) {
+       case SDEV_EVT_MEDIA_CHANGE:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       return evt;
+}
+EXPORT_SYMBOL_GPL(sdev_evt_alloc);
+
+/**
+ *     sdev_evt_send_simple - send asserted event to uevent thread
+ *     @sdev: scsi_device event occurred on
+ *     @evt_type: type of event to send
+ *     @gfpflags: GFP flags for allocation
+ *
+ *     Assert scsi device event asynchronously, given an event type.
+ */
+void sdev_evt_send_simple(struct scsi_device *sdev,
+                         enum scsi_device_event evt_type, gfp_t gfpflags)
+{
+       struct scsi_event *evt = sdev_evt_alloc(evt_type, gfpflags);
+       if (!evt) {
+               sdev_printk(KERN_ERR, sdev, "event %d eaten due to OOM\n",
+                           evt_type);
+               return;
+       }
+
+       sdev_evt_send(sdev, evt);
+}
+EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
+
 /**
  *     scsi_device_quiesce - Block user issued commands.
  *     @sdev:  scsi device to quiesce.
@@ -1990,7 +2293,7 @@ EXPORT_SYMBOL(scsi_device_set_state);
  *     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)
 {
@@ -2015,7 +2318,7 @@ EXPORT_SYMBOL(scsi_device_quiesce);
  *     queues.
  *
  *     Must be called with user context, may sleep.
- **/
+ */
 void
 scsi_device_resume(struct scsi_device *sdev)
 {
@@ -2052,8 +2355,7 @@ scsi_target_resume(struct scsi_target *starget)
 EXPORT_SYMBOL(scsi_target_resume);
 
 /**
- * scsi_internal_device_block - internal function to put a device
- *                             temporarily into the SDEV_BLOCK state
+ * 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
@@ -2068,7 +2370,7 @@ EXPORT_SYMBOL(scsi_target_resume);
  *     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)
 {
@@ -2108,7 +2410,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  *     (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)
 {
@@ -2186,25 +2488,26 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
 
 /**
  * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
- * @sg:                scatter-gather list
+ * @sgl:       scatter-gather list
  * @sg_count:  number of segments in sg
  * @offset:    offset in bytes into sg, on return offset into the mapped area
  * @len:       bytes to map, on return number of bytes mapped
  *
  * Returns virtual address of the start of the mapped page
  */
-void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
+void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
                          size_t *offset, size_t *len)
 {
        int i;
        size_t sg_len = 0, len_complete = 0;
+       struct scatterlist *sg;
        struct page *page;
 
        WARN_ON(!irqs_disabled());
 
-       for (i = 0; i < sg_count; i++) {
+       for_each_sg(sgl, sg, sg_count, i) {
                len_complete = sg_len; /* Complete sg-entries */
-               sg_len += sg[i].length;
+               sg_len += sg->length;
                if (sg_len > *offset)
                        break;
        }
@@ -2218,10 +2521,10 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
        }
 
        /* Offset starting from the beginning of first page in this sg-entry */
-       *offset = *offset - len_complete + sg[i].offset;
+       *offset = *offset - len_complete + sg->offset;
 
        /* Assumption: contiguous pages can be accessed as "page + i" */
-       page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT));
+       page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT));
        *offset &= ~PAGE_MASK;
 
        /* Bytes in this sg-entry from *offset to the end of the page */
@@ -2234,8 +2537,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 EXPORT_SYMBOL(scsi_kmap_atomic_sg);
 
 /**
- * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
- *                        mapped with scsi_kmap_atomic_sg
+ * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg
  * @virt:      virtual address to be unmapped
  */
 void scsi_kunmap_atomic_sg(void *virt)