Skip to content

Commit

Permalink
target: Make all control CDBs scatter-gather
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andy Grover authored and Nicholas Bellinger committed Jul 22, 2011
1 parent e22a7f0 commit 05d1c7c
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 225 deletions.
42 changes: 31 additions & 11 deletions drivers/target/target_core_alua.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
struct se_port *port;
struct t10_alua_tg_pt_gp *tg_pt_gp;
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
unsigned char *buf = (unsigned char *)cmd->t_task_buf;
unsigned char *buf;
u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
Target port group descriptor */

buf = transport_kmap_first_data_page(cmd);

spin_lock(&su_dev->t10_alua.tg_pt_gps_lock);
list_for_each_entry(tg_pt_gp, &su_dev->t10_alua.tg_pt_gps_list,
tg_pt_gp_list) {
Expand Down Expand Up @@ -141,6 +143,8 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd)
buf[2] = ((rd_len >> 8) & 0xff);
buf[3] = (rd_len & 0xff);

transport_kunmap_first_data_page(cmd);

return 0;
}

Expand All @@ -157,39 +161,47 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)
struct se_node_acl *nacl = cmd->se_sess->se_node_acl;
struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;
struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;
unsigned char *buf = (unsigned char *)cmd->t_task_buf;
unsigned char *ptr = &buf[4]; /* Skip over RESERVED area in header */
unsigned char *buf;
unsigned char *ptr;
u32 len = 4; /* Skip over RESERVED area in header */
int alua_access_state, primary = 0, rc;
u16 tg_pt_id, rtpi;

if (!(l_port))
return PYX_TRANSPORT_LU_COMM_FAILURE;

buf = transport_kmap_first_data_page(cmd);

/*
* Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed
* for the local tg_pt_gp.
*/
l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem;
if (!(l_tg_pt_gp_mem)) {
printk(KERN_ERR "Unable to access l_port->sep_alua_tg_pt_gp_mem\n");
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
goto out;
}
spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp;
if (!(l_tg_pt_gp)) {
spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
printk(KERN_ERR "Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n");
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
goto out;
}
rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA);
spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);

if (!(rc)) {
printk(KERN_INFO "Unable to process SET_TARGET_PORT_GROUPS"
" while TPGS_EXPLICT_ALUA is disabled\n");
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
goto out;
}

ptr = &buf[4]; /* Skip over RESERVED area in header */

while (len < cmd->data_length) {
alua_access_state = (ptr[0] & 0x0f);
/*
Expand All @@ -209,7 +221,8 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)
* REQUEST, and the additional sense code set to INVALID
* FIELD IN PARAMETER LIST.
*/
return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
goto out;
}
rc = -1;
/*
Expand Down Expand Up @@ -260,8 +273,10 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)
* If not matching target port group ID can be located
* throw an exception with ASCQ: INVALID_PARAMETER_LIST
*/
if (rc != 0)
return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
if (rc != 0) {
rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
goto out;
}
} else {
/*
* Extact the RELATIVE TARGET PORT IDENTIFIER to identify
Expand Down Expand Up @@ -295,14 +310,19 @@ int core_emulate_set_target_port_groups(struct se_cmd *cmd)
* be located, throw an exception with ASCQ:
* INVALID_PARAMETER_LIST
*/
if (rc != 0)
return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
if (rc != 0) {
rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
goto out;
}
}

ptr += 4;
len += 4;
}

out:
transport_kunmap_first_data_page(cmd);

return 0;
}

Expand Down
69 changes: 53 additions & 16 deletions drivers/target/target_core_cdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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 */
Expand All @@ -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");
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -705,16 +718,20 @@ 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;
}

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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -969,6 +997,9 @@ target_emulate_request_sense(struct se_cmd *cmd)
buf[7] = 0x0A;
}

end:
transport_kunmap_first_data_page(cmd);

return 0;
}

Expand All @@ -981,18 +1012,21 @@ 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 */
offset = 8;
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);
Expand All @@ -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;
Expand All @@ -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;
}

/*
Expand Down
5 changes: 4 additions & 1 deletion drivers/target/target_core_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
struct se_lun *se_lun;
struct se_session *se_sess = se_cmd->se_sess;
struct se_task *se_task;
unsigned char *buf = se_cmd->t_task_buf;
unsigned char *buf;
u32 cdb_offset = 0, lun_count = 0, offset = 8, i;

list_for_each_entry(se_task, &se_cmd->t_task_list, t_list)
Expand All @@ -668,6 +668,8 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
return PYX_TRANSPORT_LU_COMM_FAILURE;
}

buf = transport_kmap_first_data_page(se_cmd);

/*
* If no struct se_session pointer is present, this struct se_cmd is
* coming via a target_core_mod PASSTHROUGH op, and not through
Expand Down Expand Up @@ -704,6 +706,7 @@ int transport_core_report_lun_response(struct se_cmd *se_cmd)
* See SPC3 r07, page 159.
*/
done:
transport_kunmap_first_data_page(se_cmd);
lun_count *= 8;
buf[0] = ((lun_count >> 24) & 0xff);
buf[1] = ((lun_count >> 16) & 0xff);
Expand Down
Loading

0 comments on commit 05d1c7c

Please sign in to comment.