From d2227f84ba0e97906153ac83db13213fb2e3938d Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 16 Jan 2012 16:57:08 -0800 Subject: target: Allow control CDBs with data > 1 page commit 4949314c7283ea4f9ade182ca599583b89f7edd6 upstream. We need to handle >1 page control cdbs, so extend the code to do a vmap if bigger than 1 page. It seems like kmap() is still preferable if just a page, fewer TLB shootdowns(?), so keep using that when possible. Rename function pair for their new scope. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_alua.c | 8 +++--- drivers/target/target_core_cdb.c | 28 ++++++++++----------- drivers/target/target_core_device.c | 4 +-- drivers/target/target_core_pr.c | 38 ++++++++++++++-------------- drivers/target/target_core_pscsi.c | 4 +-- drivers/target/target_core_transport.c | 45 +++++++++++++++++++++++++--------- include/target/target_core_base.h | 1 + include/target/target_core_transport.h | 4 +-- 8 files changed, 78 insertions(+), 54 deletions(-) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1dcbef499d6..1d24512f173 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -79,7 +79,7 @@ int target_emulate_report_target_port_groups(struct se_task *task) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(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, @@ -164,7 +164,7 @@ int target_emulate_report_target_port_groups(struct se_task *task) buf[2] = ((rd_len >> 8) & 0xff); buf[3] = (rd_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -195,7 +195,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed @@ -352,7 +352,7 @@ int target_emulate_set_target_port_groups(struct se_task *task) } out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); return 0; diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 251e48f2f5e..8facd330cc3 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -82,7 +82,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); if (dev == tpg->tpg_virt_lun0.lun_se_dev) { buf[0] = 0x3f; /* Not connected */ @@ -135,7 +135,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd) buf[4] = 31; /* Set additional length to 31 */ out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -726,7 +726,7 @@ int target_emulate_inquiry(struct se_task *task) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = dev->transport->get_device_type(dev); @@ -743,7 +743,7 @@ int target_emulate_inquiry(struct se_task *task) ret = -EINVAL; out_unmap: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); out: if (!ret) { task->task_scsi_status = GOOD; @@ -765,7 +765,7 @@ int target_emulate_readcapacity(struct se_task *task) else blocks = (u32)blocks_long; - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = (blocks >> 24) & 0xff; buf[1] = (blocks >> 16) & 0xff; @@ -781,7 +781,7 @@ int target_emulate_readcapacity(struct se_task *task) 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); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -795,7 +795,7 @@ int target_emulate_readcapacity_16(struct se_task *task) unsigned char *buf; unsigned long long blocks = dev->transport->get_blocks(dev); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = (blocks >> 56) & 0xff; buf[1] = (blocks >> 48) & 0xff; @@ -816,7 +816,7 @@ int target_emulate_readcapacity_16(struct se_task *task) 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); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -1029,9 +1029,9 @@ int target_emulate_modesense(struct se_task *task) offset = cmd->data_length; } - rbuf = transport_kmap_first_data_page(cmd); + rbuf = transport_kmap_data_sg(cmd); memcpy(rbuf, buf, offset); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); @@ -1053,7 +1053,7 @@ int target_emulate_request_sense(struct se_task *task) return -ENOSYS; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { /* @@ -1099,7 +1099,7 @@ int target_emulate_request_sense(struct se_task *task) } end: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); task->task_scsi_status = GOOD; transport_complete_task(task, 1); return 0; @@ -1133,7 +1133,7 @@ int target_emulate_unmap(struct se_task *task) dl = get_unaligned_be16(&cdb[0]); bd_dl = get_unaligned_be16(&cdb[2]); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); ptr = &buf[offset]; pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu" @@ -1157,7 +1157,7 @@ int target_emulate_unmap(struct se_task *task) } err: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); if (!ret) { task->task_scsi_status = GOOD; transport_complete_task(task, 1); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9b863942547..19f8aca0809 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -658,7 +658,7 @@ int target_report_luns(struct se_task *se_task) unsigned char *buf; u32 cdb_offset = 0, lun_count = 0, offset = 8, i; - buf = transport_kmap_first_data_page(se_cmd); + buf = (unsigned char *) transport_kmap_data_sg(se_cmd); /* * If no struct se_session pointer is present, this struct se_cmd is @@ -696,7 +696,7 @@ int target_report_luns(struct se_task *se_task) * See SPC3 r07, page 159. */ done: - transport_kunmap_first_data_page(se_cmd); + transport_kunmap_data_sg(se_cmd); lun_count *= 8; buf[0] = ((lun_count >> 24) & 0xff); buf[1] = ((lun_count >> 16) & 0xff); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 9119d92df87..778c1a67854 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1538,7 +1538,7 @@ static int core_scsi3_decode_spec_i_port( tidh_new->dest_local_nexus = 1; list_add_tail(&tidh_new->dest_list, &tid_dest_list); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * For a PERSISTENT RESERVE OUT specify initiator ports payload, * first extract TransportID Parameter Data Length, and make sure @@ -1789,7 +1789,7 @@ static int core_scsi3_decode_spec_i_port( } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); /* * Go ahead and create a registrations from tid_dest_list for the @@ -1837,7 +1837,7 @@ static int core_scsi3_decode_spec_i_port( return 0; out: - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); /* * For the failure case, release everything from tid_dest_list * including *dest_pr_reg and the configfs dependances.. @@ -3429,14 +3429,14 @@ static int core_scsi3_emulate_pro_register_and_move( * will be moved to for the TransportID containing SCSI initiator WWN * information. */ - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); rtpi = (buf[18] & 0xff) << 8; rtpi |= buf[19] & 0xff; tid_len = (buf[20] & 0xff) << 24; tid_len |= (buf[21] & 0xff) << 16; tid_len |= (buf[22] & 0xff) << 8; tid_len |= buf[23] & 0xff; - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; if ((tid_len + 24) != cmd->data_length) { @@ -3488,7 +3488,7 @@ static int core_scsi3_emulate_pro_register_and_move( return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); proto_ident = (buf[24] & 0x0f); #if 0 pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" @@ -3522,7 +3522,7 @@ static int core_scsi3_emulate_pro_register_and_move( goto out; } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s" @@ -3787,13 +3787,13 @@ after_iport_check: " REGISTER_AND_MOVE\n"); } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); core_scsi3_put_pr_reg(dest_pr_reg); return 0; out: if (buf) - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); if (dest_se_deve) core_scsi3_lunacl_undepend_item(dest_se_deve); if (dest_node_acl) @@ -3867,7 +3867,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) scope = (cdb[2] & 0xf0); type = (cdb[2] & 0x0f); - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); /* * From PERSISTENT_RESERVE_OUT parameter list (payload) */ @@ -3885,7 +3885,7 @@ int target_scsi3_emulate_pr_out(struct se_task *task) aptpl = (buf[17] & 0x01); unreg = (buf[17] & 0x02); } - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); buf = NULL; /* @@ -3985,7 +3985,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); @@ -4019,7 +4019,7 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) buf[6] = ((add_len >> 8) & 0xff); buf[7] = (add_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4045,7 +4045,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); buf[2] = ((su_dev->t10_pr.pr_generation >> 8) & 0xff); @@ -4104,7 +4104,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) err: spin_unlock(&se_dev->dev_reservation_lock); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4128,7 +4128,7 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((add_len << 8) & 0xff); buf[1] = (add_len & 0xff); @@ -4160,7 +4160,7 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */ buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */ - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } @@ -4190,7 +4190,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) return -EINVAL; } - buf = transport_kmap_first_data_page(cmd); + buf = transport_kmap_data_sg(cmd); buf[0] = ((su_dev->t10_pr.pr_generation >> 24) & 0xff); buf[1] = ((su_dev->t10_pr.pr_generation >> 16) & 0xff); @@ -4311,7 +4311,7 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) buf[6] = ((add_len >> 8) & 0xff); buf[7] = (add_len & 0xff); - transport_kunmap_first_data_page(cmd); + transport_kunmap_data_sg(cmd); return 0; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 8b15e56b038..5c12137c526 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -695,7 +695,7 @@ static int pscsi_transport_complete(struct se_task *task) if (task->task_se_cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { - unsigned char *buf = transport_kmap_first_data_page(task->task_se_cmd); + unsigned char *buf = transport_kmap_data_sg(task->task_se_cmd); if (cdb[0] == MODE_SENSE_10) { if (!(buf[3] & 0x80)) @@ -705,7 +705,7 @@ static int pscsi_transport_complete(struct se_task *task) buf[2] |= 0x80; } - transport_kunmap_first_data_page(task->task_se_cmd); + transport_kunmap_data_sg(task->task_se_cmd); } } after_mode_sense: diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 861628eb2da..e4ddb93a827 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3053,11 +3053,6 @@ static int transport_generic_cmd_sequencer( (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) goto out_unsupported_cdb; - /* Let's limit control cdbs to a page, for simplicity's sake. */ - if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) && - size > PAGE_SIZE) - goto out_invalid_cdb_field; - transport_set_supported_SAM_opcode(cmd); return ret; @@ -3435,9 +3430,11 @@ int transport_generic_map_mem_to_cmd( } EXPORT_SYMBOL(transport_generic_map_mem_to_cmd); -void *transport_kmap_first_data_page(struct se_cmd *cmd) +void *transport_kmap_data_sg(struct se_cmd *cmd) { struct scatterlist *sg = cmd->t_data_sg; + struct page **pages; + int i; BUG_ON(!sg); /* @@ -3445,15 +3442,41 @@ void *transport_kmap_first_data_page(struct se_cmd *cmd) * tcm_loop who may be using a contig buffer from the SCSI midlayer for * control CDBs passed as SGLs via transport_generic_map_mem_to_cmd() */ - return kmap(sg_page(sg)) + sg->offset; + if (!cmd->t_data_nents) + return NULL; + else if (cmd->t_data_nents == 1) + return kmap(sg_page(sg)) + sg->offset; + + /* >1 page. use vmap */ + pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL); + if (!pages) + return NULL; + + /* convert sg[] to pages[] */ + for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) { + pages[i] = sg_page(sg); + } + + cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL); + kfree(pages); + if (!cmd->t_data_vmap) + return NULL; + + return cmd->t_data_vmap + cmd->t_data_sg[0].offset; } -EXPORT_SYMBOL(transport_kmap_first_data_page); +EXPORT_SYMBOL(transport_kmap_data_sg); -void transport_kunmap_first_data_page(struct se_cmd *cmd) +void transport_kunmap_data_sg(struct se_cmd *cmd) { - kunmap(sg_page(cmd->t_data_sg)); + if (!cmd->t_data_nents) + return; + else if (cmd->t_data_nents == 1) + kunmap(sg_page(cmd->t_data_sg)); + + vunmap(cmd->t_data_vmap); + cmd->t_data_vmap = NULL; } -EXPORT_SYMBOL(transport_kunmap_first_data_page); +EXPORT_SYMBOL(transport_kunmap_data_sg); static int transport_generic_get_mem(struct se_cmd *cmd) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index a79886c86e9..94bbec38fd0 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -486,6 +486,7 @@ struct se_cmd { struct scatterlist *t_data_sg; unsigned int t_data_nents; + void *t_data_vmap; struct scatterlist *t_bidi_data_sg; unsigned int t_bidi_data_nents; diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index dac4f2d859f..72751e85ea1 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h @@ -129,8 +129,8 @@ extern void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); -void *transport_kmap_first_data_page(struct se_cmd *cmd); -void transport_kunmap_first_data_page(struct se_cmd *cmd); +void *transport_kmap_data_sg(struct se_cmd *); +void transport_kunmap_data_sg(struct se_cmd *); extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); extern int transport_handle_cdb_direct(struct se_cmd *); extern int transport_generic_handle_cdb_map(struct se_cmd *); -- cgit v1.2.3-18-g5258