diff options
author | Andy Grover <agrover@redhat.com> | 2011-07-20 19:13:28 +0000 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-07-22 09:37:48 +0000 |
commit | 05d1c7c0d0db4cc25548d9aadebb416888a82327 (patch) | |
tree | 290243526d188a7f6a683b0e13a63c7207471fa1 /drivers/target/target_core_cdb.c | |
parent | e22a7f075226c51f3f71b922e9eeb4f99fac1475 (diff) |
target: Make all control CDBs scatter-gather
Previously, some control CDBs did not allocate memory in pages for their
data buffer, but just did a kmalloc. This patch makes all cdbs allocate
pages.
This has the benefit of streamlining some paths that had to behave
differently when we used two allocation methods. The downside is that
all accesses to the data buffer need to kmap it before use, and need to
handle data in page-sized chunks if more than a page is needed for a given
command's data buffer.
Finally, note that cdbs with no data buffers are handled a little
differently. Before, SCSI_NON_DATA_CDBs would not call get_mem at all
(they'd be in the final else in transport_allocate_resources) but now
these will make it into generic_get_mem, but just not allocate any
buffers.
Signed-off-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_cdb.c')
-rw-r--r-- | drivers/target/target_core_cdb.c | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 432253034de..418282d926f 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -66,7 +66,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) { struct se_lun *lun = cmd->se_lun; struct se_device *dev = cmd->se_dev; - unsigned char *buf = cmd->t_task_buf; + unsigned char *buf; /* * Make sure we at least have 6 bytes of INQUIRY response @@ -78,6 +78,8 @@ target_emulate_inquiry_std(struct se_cmd *cmd) return -EINVAL; } + buf = transport_kmap_first_data_page(cmd); + buf[0] = dev->transport->get_device_type(dev); if (buf[0] == TYPE_TAPE) buf[1] = 0x80; @@ -91,7 +93,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) if (cmd->data_length < 8) { buf[4] = 1; /* Set additional length to 1 */ - return 0; + goto out; } buf[7] = 0x32; /* Sync=1 and CmdQue=1 */ @@ -102,7 +104,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) */ if (cmd->data_length < 36) { buf[4] = 3; /* Set additional length to 3 */ - return 0; + goto out; } snprintf((unsigned char *)&buf[8], 8, "LIO-ORG"); @@ -111,6 +113,9 @@ target_emulate_inquiry_std(struct se_cmd *cmd) snprintf((unsigned char *)&buf[32], 4, "%s", &dev->se_sub_dev->t10_wwn.revision[0]); buf[4] = 31; /* Set additional length to 31 */ + +out: + transport_kunmap_first_data_page(cmd); return 0; } @@ -647,9 +652,9 @@ static int target_emulate_inquiry(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - unsigned char *buf = cmd->t_task_buf; + unsigned char *buf; unsigned char *cdb = cmd->t_task_cdb; - int p; + int p, ret; if (!(cdb[1] & 0x1)) return target_emulate_inquiry_std(cmd); @@ -666,14 +671,20 @@ target_emulate_inquiry(struct se_cmd *cmd) " too small for EVPD=1\n", cmd->data_length); return -EINVAL; } + + buf = transport_kmap_first_data_page(cmd); + buf[0] = dev->transport->get_device_type(dev); for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) if (cdb[2] == evpd_handlers[p].page) { buf[1] = cdb[2]; - return evpd_handlers[p].emulate(cmd, buf); + ret = evpd_handlers[p].emulate(cmd, buf); + transport_kunmap_first_data_page(cmd); + return ret; } + transport_kunmap_first_data_page(cmd); printk(KERN_ERR "Unknown VPD Code: 0x%02x\n", cdb[2]); return -EINVAL; } @@ -682,7 +693,7 @@ static int target_emulate_readcapacity(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - unsigned char *buf = cmd->t_task_buf; + unsigned char *buf; unsigned long long blocks_long = dev->transport->get_blocks(dev); u32 blocks; @@ -691,6 +702,8 @@ target_emulate_readcapacity(struct se_cmd *cmd) else blocks = (u32)blocks_long; + buf = transport_kmap_first_data_page(cmd); + buf[0] = (blocks >> 24) & 0xff; buf[1] = (blocks >> 16) & 0xff; buf[2] = (blocks >> 8) & 0xff; @@ -705,6 +718,8 @@ target_emulate_readcapacity(struct se_cmd *cmd) if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) put_unaligned_be32(0xFFFFFFFF, &buf[0]); + transport_kunmap_first_data_page(cmd); + return 0; } @@ -712,9 +727,11 @@ static int target_emulate_readcapacity_16(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - unsigned char *buf = cmd->t_task_buf; + unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); + buf = transport_kmap_first_data_page(cmd); + buf[0] = (blocks >> 56) & 0xff; buf[1] = (blocks >> 48) & 0xff; buf[2] = (blocks >> 40) & 0xff; @@ -734,6 +751,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd) if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws) buf[14] = 0x80; + transport_kunmap_first_data_page(cmd); + return 0; } @@ -848,7 +867,7 @@ target_emulate_modesense(struct se_cmd *cmd, int ten) { struct se_device *dev = cmd->se_dev; char *cdb = cmd->t_task_cdb; - unsigned char *rbuf = cmd->t_task_buf; + unsigned char *rbuf; int type = dev->transport->get_device_type(dev); int offset = (ten) ? 8 : 4; int length = 0; @@ -911,7 +930,10 @@ target_emulate_modesense(struct se_cmd *cmd, int ten) if ((offset + 1) > cmd->data_length) offset = cmd->data_length; } + + rbuf = transport_kmap_first_data_page(cmd); memcpy(rbuf, buf, offset); + transport_kunmap_first_data_page(cmd); return 0; } @@ -920,14 +942,18 @@ static int target_emulate_request_sense(struct se_cmd *cmd) { unsigned char *cdb = cmd->t_task_cdb; - unsigned char *buf = cmd->t_task_buf; + unsigned char *buf; u8 ua_asc = 0, ua_ascq = 0; + int err = 0; if (cdb[1] & 0x01) { printk(KERN_ERR "REQUEST_SENSE description emulation not" " supported\n"); return PYX_TRANSPORT_INVALID_CDB_FIELD; } + + buf = transport_kmap_first_data_page(cmd); + if (!(core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq))) { /* * CURRENT ERROR, UNIT ATTENTION @@ -940,7 +966,8 @@ target_emulate_request_sense(struct se_cmd *cmd) */ if (cmd->data_length <= 18) { buf[7] = 0x00; - return 0; + err = -EINVAL; + goto end; } /* * The Additional Sense Code (ASC) from the UNIT ATTENTION @@ -960,7 +987,8 @@ target_emulate_request_sense(struct se_cmd *cmd) */ if (cmd->data_length <= 18) { buf[7] = 0x00; - return 0; + err = -EINVAL; + goto end; } /* * NO ADDITIONAL SENSE INFORMATION @@ -969,6 +997,9 @@ target_emulate_request_sense(struct se_cmd *cmd) buf[7] = 0x0A; } +end: + transport_kunmap_first_data_page(cmd); + return 0; } @@ -981,11 +1012,11 @@ target_emulate_unmap(struct se_task *task) { struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; - unsigned char *buf = cmd->t_task_buf, *ptr = NULL; + unsigned char *buf, *ptr = NULL; unsigned char *cdb = &cmd->t_task_cdb[0]; sector_t lba; unsigned int size = cmd->data_length, range; - int ret, offset; + int ret = 0, offset; unsigned short dl, bd_dl; /* First UNMAP block descriptor starts at 8 byte offset */ @@ -993,6 +1024,9 @@ target_emulate_unmap(struct se_task *task) size -= 8; dl = get_unaligned_be16(&cdb[0]); bd_dl = get_unaligned_be16(&cdb[2]); + + buf = transport_kmap_first_data_page(cmd); + ptr = &buf[offset]; printk(KERN_INFO "UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); @@ -1007,7 +1041,7 @@ target_emulate_unmap(struct se_task *task) if (ret < 0) { printk(KERN_ERR "blkdev_issue_discard() failed: %d\n", ret); - return ret; + goto err; } ptr += 16; @@ -1016,7 +1050,10 @@ target_emulate_unmap(struct se_task *task) task->task_scsi_status = GOOD; transport_complete_task(task, 1); - return 0; +err: + transport_kunmap_first_data_page(cmd); + + return ret; } /* |