rest -= mlen;
}
out:
-
return 0;
}
-static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
- void (*done)(struct scsi_cmnd *))
-{
- struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
- int err;
-
- err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
-
- done(sc);
-
- return err;
-}
-
static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *))
{
struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
struct srp_target *target = iue->target;
- dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+ dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+ cmd->usg_sg);
+
+ if (sc->use_sg)
+ srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
spin_lock_irqsave(&target->lock, flags);
list_del(&iue->ilist);
.use_clustering = DISABLE_CLUSTERING,
.max_sectors = DEFAULT_MAX_SECTORS,
.transfer_response = ibmvstgt_cmd_done,
- .transfer_data = ibmvstgt_transfer_data,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
.tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.shost_attrs = ibmvstgt_attrs,
struct list_head hash_list;
struct request *rq;
u64 tag;
-
- void *buffer;
- unsigned bufflen;
};
#define TGT_HASH_ORDER 4
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;
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;
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,
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)
{
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;
* 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;
- }
-
- /*
- * 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 (cmd->result == SAM_STAT_CHECK_CONDITION)
+ scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
- /* 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;
+ if (len) {
+ err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
+ if (err) {
+ eprintk("%p %d\n", cmd, err);
+ err = -EAGAIN;
+ goto done;
+ }
}
- /* ask the target LLD to transfer the data to the buffer */
- err = scsi_tgt_transfer_data(cmd);
-
+ err = scsi_tgt_transfer_response(cmd);
done:
scsi_host_put(shost);
return err;
* the LLD. When the driver is finished processing the command
* the done callback is invoked.
*
+ * This is called to inform the LLD to transfer
+ * cmd->request_bufflen bytes. The cmd->use_sg speciefies the
+ * number of scatterlist entried in the command and
+ * cmd->request_buffer contains the scatterlist.
+ *
* return values: see queuecommand
*
* If the LLD accepts the cmd, it should set the result to an
/* TODO: rename */
int (* transfer_response)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
- /*
- * This is called to inform the LLD to transfer cmd->request_bufflen
- * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
- * speciefies the number of scatterlist entried in the command
- * and cmd->request_buffer contains the scatterlist.
- *
- * If the command cannot be processed in one transfer_data call
- * becuase a scatterlist within the LLD's limits cannot be
- * created then transfer_data will be called multiple times.
- * It is initially called from process context, and later
- * calls are from the interrup context.
- */
- int (* transfer_data)(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
/* Used as callback for the completion of task management request. */
int (* tsk_mgmt_response)(u64 mid, int result);