]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_tgt_lib.c
Merge branch 'linux-2.6' into for-2.6.24
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_tgt_lib.c
index 47c29a98c922b02b394261a670439c520a35661c..371b69c110bcc5403b81d4b046ba31dc9888cc9e 100644 (file)
@@ -47,9 +47,6 @@ struct scsi_tgt_cmd {
        struct list_head hash_list;
        struct request *rq;
        u64 tag;
-
-       void *buffer;
-       unsigned bufflen;
 };
 
 #define TGT_HASH_ORDER 4
@@ -330,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
        dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
 
        scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+
+       if (cmd->request_buffer)
+               scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+
        queue_work(scsi_tgtd, &tcmd->work);
 }
 
-static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
 {
        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
        int err;
@@ -346,30 +347,12 @@ static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
        case SCSI_MLQUEUE_DEVICE_BUSY:
                return -EAGAIN;
        }
-
        return 0;
 }
 
-static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
-{
-       struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
-       int err;
-
-       err = __scsi_tgt_transfer_response(cmd);
-       if (!err)
-               return;
-
-       cmd->result = DID_BUS_BUSY << 16;
-       err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
-       if (err <= 0)
-               /* the eh will have to pick this up */
-               printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-}
-
 static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 {
        struct request *rq = cmd->request;
-       struct scsi_tgt_cmd *tcmd = rq->end_io_data;
        int count;
 
        cmd->use_sg = rq->nr_phys_segments;
@@ -379,31 +362,28 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 
        cmd->request_bufflen = rq->data_len;
 
-       dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
-               rq_data_dir(rq));
+       dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
        count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
        if (likely(count <= cmd->use_sg)) {
                cmd->use_sg = count;
                return 0;
        }
 
-       eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
+       eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
        scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
        return -EINVAL;
 }
 
 /* TODO: test this crap and replace bio_map_user with new interface maybe */
 static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
-                              int rw)
+                              unsigned long uaddr, unsigned int len, int rw)
 {
        struct request_queue *q = cmd->request->q;
        struct request *rq = cmd->request;
-       void *uaddr = tcmd->buffer;
-       unsigned int len = tcmd->bufflen;
        int err;
 
-       dprintk("%lx %u\n", (unsigned long) uaddr, len);
-       err = blk_rq_map_user(q, rq, uaddr, len);
+       dprintk("%lx %u\n", uaddr, len);
+       err = blk_rq_map_user(q, rq, (void *)uaddr, len);
        if (err) {
                /*
                 * TODO: need to fixup sg_tablesize, max_segment_size,
@@ -430,45 +410,6 @@ unmap_rq:
        return err;
 }
 
-static int scsi_tgt_transfer_data(struct scsi_cmnd *);
-
-static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
-{
-       struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
-       int err;
-
-       /* should we free resources here on error ? */
-       if (cmd->result) {
-               err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
-               if (err <= 0)
-                       /* the tgt uspace eh will have to pick this up */
-                       printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-               return;
-       }
-
-       dprintk("cmd %p request_bufflen %u bufflen %u\n",
-               cmd, cmd->request_bufflen, tcmd->bufflen);
-
-       scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
-       tcmd->buffer += cmd->request_bufflen;
-       scsi_tgt_transfer_response(cmd);
-}
-
-static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
-{
-       int err;
-       struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
-
-       err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
-       switch (err) {
-               case SCSI_MLQUEUE_HOST_BUSY:
-               case SCSI_MLQUEUE_DEVICE_BUSY:
-                       return -EAGAIN;
-       default:
-               return 0;
-       }
-}
-
 static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
                                unsigned len)
 {
@@ -518,8 +459,9 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
        return rq;
 }
 
-int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
-                        unsigned long uaddr, u8 rw)
+int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+                        unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+                        u32 sense_len, u8 rw)
 {
        struct Scsi_Host *shost;
        struct scsi_cmnd *cmd;
@@ -564,36 +506,36 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
         * in the request_* values
         */
        tcmd = cmd->request->end_io_data;
-       tcmd->buffer = (void *)uaddr;
-       tcmd->bufflen = len;
        cmd->result = result;
 
-       if (!tcmd->bufflen || cmd->request_buffer) {
-               err = __scsi_tgt_transfer_response(cmd);
-               goto done;
-       }
+       if (cmd->result == SAM_STAT_CHECK_CONDITION)
+               scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
 
-       /*
-        * TODO: Do we need to handle case where request does not
-        * align with LLD.
-        */
-       err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
-       if (err) {
-               eprintk("%p %d\n", cmd, err);
-               err = -EAGAIN;
-               goto done;
-       }
+       if (len) {
+               err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
+               if (err) {
+                       /*
+                        * user-space daemon bugs or OOM
+                        * TODO: we can do better for OOM.
+                        */
+                       struct scsi_tgt_queuedata *qdata;
+                       struct list_head *head;
+                       unsigned long flags;
 
-       /* userspace failure */
-       if (cmd->result) {
-               if (status_byte(cmd->result) == CHECK_CONDITION)
-                       scsi_tgt_copy_sense(cmd, uaddr, len);
-               err = __scsi_tgt_transfer_response(cmd);
-               goto done;
-       }
-       /* ask the target LLD to transfer the data to the buffer */
-       err = scsi_tgt_transfer_data(cmd);
+                       eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n",
+                               cmd, err, uaddr, len, rw);
+
+                       qdata = shost->uspace_req_q->queuedata;
+                       head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)];
+
+                       spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+                       list_add(&tcmd->hash_list, head);
+                       spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 
+                       goto done;
+               }
+       }
+       err = scsi_tgt_transfer_response(cmd);
 done:
        scsi_host_put(shost);
        return err;
@@ -643,7 +585,7 @@ static int __init scsi_tgt_init(void)
 
        scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
                                               sizeof(struct scsi_tgt_cmd),
-                                              0, 0, NULL, NULL);
+                                              0, 0, NULL);
        if (!scsi_tgt_cmd_cache)
                return -ENOMEM;