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) {
buf[2] = ((rd_len >> 8) & 0xff);
buf[3] = (rd_len & 0xff);
+ transport_kunmap_first_data_page(cmd);
+
return 0;
}
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);
/*
* 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;
/*
* 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
* 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;
}
{
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
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;
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 */
*/
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");
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;
}
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);
" 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;
}
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;
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;
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;
}
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;
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;
}
{
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;
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;
}
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
*/
if (cmd->data_length <= 18) {
buf[7] = 0x00;
- return 0;
+ err = -EINVAL;
+ goto end;
}
/*
* The Additional Sense Code (ASC) from the UNIT ATTENTION
*/
if (cmd->data_length <= 18) {
buf[7] = 0x00;
- return 0;
+ err = -EINVAL;
+ goto end;
}
/*
* NO ADDITIONAL SENSE INFORMATION
buf[7] = 0x0A;
}
+end:
+ transport_kunmap_first_data_page(cmd);
+
return 0;
}
{
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 */
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);
if (ret < 0) {
printk(KERN_ERR "blkdev_issue_discard() failed: %d\n",
ret);
- return ret;
+ goto err;
}
ptr += 16;
task->task_scsi_status = GOOD;
transport_complete_task(task, 1);
- return 0;
+err:
+ transport_kunmap_first_data_page(cmd);
+
+ return ret;
}
/*
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)
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
* 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);
struct list_head tid_dest_list;
struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
struct target_core_fabric_ops *tmp_tf_ops;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
u32 tpdl, tid_len = 0;
*/
tidh_new->dest_local_nexus = 1;
list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+
+ buf = transport_kmap_first_data_page(cmd);
/*
* For a PERSISTENT RESERVE OUT specify initiator ports payload,
* first extract TransportID Parameter Data Length, and make sure
tid_len = 0;
}
+
+ transport_kunmap_first_data_page(cmd);
+
/*
* Go ahead and create a registrations from tid_dest_list for the
* SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl
return 0;
out:
+ transport_kunmap_first_data_page(cmd);
/*
* For the failure case, release everything from tid_dest_list
* including *dest_pr_reg and the configfs dependances..
struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
unsigned char *initiator_str;
char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
u32 tid_len, tmp_tid_len;
core_scsi3_put_pr_reg(pr_reg);
return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
}
+
/*
* Determine the Relative Target Port Identifier where the reservation
* will be moved to for the TransportID containing SCSI initiator WWN
* information.
*/
+ buf = transport_kmap_first_data_page(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);
+ buf = NULL;
if ((tid_len + 24) != cmd->data_length) {
printk(KERN_ERR "SPC-3 PR: Illegal tid_len: %u + 24 byte header"
core_scsi3_put_pr_reg(pr_reg);
return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
}
+
+ buf = transport_kmap_first_data_page(cmd);
proto_ident = (buf[24] & 0x0f);
#if 0
printk("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:"
goto out;
}
+ transport_kunmap_first_data_page(cmd);
+ buf = NULL;
+
printk(KERN_INFO "SPC-3 PR [%s] Extracted initiator %s identifier: %s"
" %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ?
"port" : "device", initiator_str, (iport_ptr != NULL) ?
" REGISTER_AND_MOVE\n");
}
+ transport_kunmap_first_data_page(cmd);
+
core_scsi3_put_pr_reg(dest_pr_reg);
return 0;
out:
+ if (buf)
+ transport_kunmap_first_data_page(cmd);
if (dest_se_deve)
core_scsi3_lunacl_undepend_item(dest_se_deve);
if (dest_node_acl)
*/
static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
{
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
u64 res_key, sa_res_key;
int sa, scope, type, aptpl;
int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
sa = (cdb[1] & 0x1f);
scope = (cdb[2] & 0xf0);
type = (cdb[2] & 0x0f);
+
+ buf = transport_kmap_first_data_page(cmd);
/*
* From PERSISTENT_RESERVE_OUT parameter list (payload)
*/
aptpl = (buf[17] & 0x01);
unreg = (buf[17] & 0x02);
}
+ transport_kunmap_first_data_page(cmd);
+ buf = NULL;
+
/*
* SPEC_I_PT=1 is only valid for Service action: REGISTER
*/
struct se_device *se_dev = cmd->se_dev;
struct se_subsystem_dev *su_dev = se_dev->se_sub_dev;
struct t10_pr_registration *pr_reg;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
u32 add_len = 0, off = 8;
if (cmd->data_length < 8) {
return PYX_TRANSPORT_INVALID_CDB_FIELD;
}
+ buf = transport_kmap_first_data_page(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);
buf[6] = ((add_len >> 8) & 0xff);
buf[7] = (add_len & 0xff);
+ transport_kunmap_first_data_page(cmd);
+
return 0;
}
struct se_device *se_dev = cmd->se_dev;
struct se_subsystem_dev *su_dev = se_dev->se_sub_dev;
struct t10_pr_registration *pr_reg;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
u64 pr_res_key;
u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */
return PYX_TRANSPORT_INVALID_CDB_FIELD;
}
+ buf = transport_kmap_first_data_page(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);
buf[6] = ((add_len >> 8) & 0xff);
buf[7] = (add_len & 0xff);
- if (cmd->data_length < 22) {
- spin_unlock(&se_dev->dev_reservation_lock);
- return 0;
- }
+ if (cmd->data_length < 22)
+ goto err;
+
/*
* Set the Reservation key.
*
buf[21] = (pr_reg->pr_res_scope & 0xf0) |
(pr_reg->pr_res_type & 0x0f);
}
+
+err:
spin_unlock(&se_dev->dev_reservation_lock);
+ transport_kunmap_first_data_page(cmd);
return 0;
}
{
struct se_device *dev = cmd->se_dev;
struct t10_reservation *pr_tmpl = &dev->se_sub_dev->t10_pr;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
u16 add_len = 8; /* Hardcoded to 8. */
if (cmd->data_length < 6) {
return PYX_TRANSPORT_INVALID_CDB_FIELD;
}
+ buf = transport_kmap_first_data_page(cmd);
+
buf[0] = ((add_len << 8) & 0xff);
buf[1] = (add_len & 0xff);
buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */
buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
+ transport_kunmap_first_data_page(cmd);
+
return 0;
}
struct se_portal_group *se_tpg;
struct t10_pr_registration *pr_reg, *pr_reg_tmp;
struct t10_reservation *pr_tmpl = &se_dev->se_sub_dev->t10_pr;
- unsigned char *buf = (unsigned char *)cmd->t_task_buf;
+ unsigned char *buf;
u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
u32 off = 8; /* off into first Full Status descriptor */
int format_code = 0;
return PYX_TRANSPORT_INVALID_CDB_FIELD;
}
+ buf = transport_kmap_first_data_page(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);
buf[6] = ((add_len >> 8) & 0xff);
buf[7] = (add_len & 0xff);
+ transport_kunmap_first_data_page(cmd);
+
return 0;
}
if (task->task_se_cmd->se_deve->lun_flags &
TRANSPORT_LUNFLAGS_READ_ONLY) {
- unsigned char *buf = task->task_se_cmd->t_task_buf;
+ unsigned char *buf = transport_kmap_first_data_page(task->task_se_cmd);
if (cdb[0] == MODE_SENSE_10) {
if (!(buf[3] & 0x80))
if (!(buf[2] & 0x80))
buf[2] |= 0x80;
}
+
+ transport_kunmap_first_data_page(task->task_se_cmd);
}
}
after_mode_sense:
return 0;
}
-/* pscsi_map_task_non_SG():
- *
- *
- */
-static int pscsi_map_task_non_SG(struct se_task *task)
-{
- struct se_cmd *cmd = task->task_se_cmd;
- struct pscsi_plugin_task *pt = PSCSI_TASK(task);
- struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
- int ret = 0;
-
- if (pscsi_blk_get_request(task) < 0)
- return PYX_TRANSPORT_LU_COMM_FAILURE;
-
- if (!task->task_size)
- return 0;
-
- ret = blk_rq_map_kern(pdv->pdv_sd->request_queue,
- pt->pscsi_req, cmd->t_task_buf,
- task->task_size, GFP_KERNEL);
- if (ret < 0) {
- printk(KERN_ERR "PSCSI: blk_rq_map_kern() failed: %d\n", ret);
- return PYX_TRANSPORT_LU_COMM_FAILURE;
- }
- return 0;
-}
-
static int pscsi_CDB_none(struct se_task *task)
{
return pscsi_blk_get_request(task);
.owner = THIS_MODULE,
.transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
.cdb_none = pscsi_CDB_none,
- .map_task_non_SG = pscsi_map_task_non_SG,
.map_task_SG = pscsi_map_task_SG,
.attach_hba = pscsi_attach_hba,
.detach_hba = pscsi_detach_hba,
unsigned long long starting_lba, u32 sectors,
enum dma_data_direction data_direction,
struct list_head *mem_list, int set_counts);
-static int transport_generic_get_mem(struct se_cmd *cmd, u32 length);
+static int transport_generic_get_mem(struct se_cmd *cmd);
static int transport_generic_remove(struct se_cmd *cmd,
int session_reinstatement);
static int transport_cmd_get_valid_sectors(struct se_cmd *cmd);
transport_generic_remove(cmd, 0);
}
-static int
-transport_generic_allocate_buf(struct se_cmd *cmd, u32 data_length)
-{
- unsigned char *buf;
-
- buf = kzalloc(data_length, GFP_KERNEL);
- if (!(buf)) {
- printk(KERN_ERR "Unable to allocate memory for buffer\n");
- return -ENOMEM;
- }
-
- cmd->t_tasks_se_num = 0;
- cmd->t_task_buf = buf;
-
- return 0;
-}
-
static inline u32 transport_lba_21(unsigned char *cdb)
{
return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
return -1;
}
-static int transport_allocate_resources(struct se_cmd *cmd)
-{
- u32 length = cmd->data_length;
-
- if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
- (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB))
- return transport_generic_get_mem(cmd, length);
- else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB)
- return transport_generic_allocate_buf(cmd, length);
- else
- return 0;
-}
-
static int
transport_handle_reservation_conflict(struct se_cmd *cmd)
{
/* GPCMD_SEND_KEY from multi media commands */
size = (cdb[8] << 8) + cdb[9];
}
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case MODE_SELECT:
size = cdb[4];
break;
case MODE_SENSE:
size = cdb[4];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case MODE_SENSE_10:
case GPCMD_READ_BUFFER_CAPACITY:
case LOG_SELECT:
case LOG_SENSE:
size = (cdb[7] << 8) + cdb[8];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case READ_BLOCK_LIMITS:
size = READ_BLOCK_LEN;
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case GPCMD_GET_CONFIGURATION:
case GPCMD_READ_FORMAT_CAPACITIES:
SPC3_PERSISTENT_RESERVATIONS) ?
core_scsi3_emulate_pr : NULL;
size = (cdb[7] << 8) + cdb[8];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case GPCMD_MECHANISM_STATUS:
case GPCMD_READ_DVD_STRUCTURE:
break;
case READ_POSITION:
size = READ_POSITION_LEN;
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case MAINTENANCE_OUT:
if (dev->transport->get_device_type(dev) != TYPE_ROM) {
/* GPCMD_REPORT_KEY from multi media commands */
size = (cdb[8] << 8) + cdb[9];
}
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case INQUIRY:
size = (cdb[3] << 8) + cdb[4];
*/
if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
cmd->sam_task_attr = MSG_HEAD_TAG;
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case READ_BUFFER:
size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case READ_CAPACITY:
size = READ_CAP_LEN;
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case READ_MEDIA_SERIAL_NUMBER:
case SECURITY_PROTOCOL_IN:
case SECURITY_PROTOCOL_OUT:
size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case SERVICE_ACTION_IN:
case ACCESS_CONTROL_IN:
case WRITE_ATTRIBUTE:
size = (cdb[10] << 24) | (cdb[11] << 16) |
(cdb[12] << 8) | cdb[13];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case RECEIVE_DIAGNOSTIC:
case SEND_DIAGNOSTIC:
size = (cdb[3] << 8) | cdb[4];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */
#if 0
case GPCMD_READ_CD:
sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
size = (2336 * sectors);
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
#endif
case READ_TOC:
size = cdb[8];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case REQUEST_SENSE:
size = cdb[4];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case READ_ELEMENT_STATUS:
size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case WRITE_BUFFER:
size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case RESERVE:
case RESERVE_10:
break;
case UNMAP:
size = get_unaligned_be16(&cdb[7]);
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
case WRITE_SAME_16:
sectors = transport_get_sectors_16(cdb, cmd, §or_ret);
*/
if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
cmd->sam_task_attr = MSG_HEAD_TAG;
- cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break;
default:
printk(KERN_WARNING "TARGET_CORE[%s]: Unsupported SCSI Opcode"
cmd->data_length;
}
spin_unlock(&cmd->se_lun->lun_sep_lock);
- /*
- * If enabled by TCM fabric module pre-registered SGL
- * memory, perform the memcpy() from the TCM internal
- * contiguous buffer back to the original SGL.
- */
- if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
- sg_copy_from_buffer(cmd->t_task_pt_sgl,
- cmd->t_task_pt_sgl_num,
- cmd->t_task_buf,
- cmd->data_length);
ret = cmd->se_tfo->queue_data_in(cmd);
if (ret == -EAGAIN)
if (cmd->se_dev->transport->do_se_mem_map)
free_page = 0;
- if (cmd->t_task_buf) {
- kfree(cmd->t_task_buf);
- cmd->t_task_buf = NULL;
- return;
- }
-
list_for_each_entry_safe(se_mem, se_mem_tmp,
&cmd->t_mem_list, se_list) {
/*
cmd->t_tasks_se_bidi_num = ret;
}
cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
-
- } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
- if (sgl_bidi || sgl_bidi_count) {
- printk(KERN_ERR "BIDI-Commands not supported using "
- "SCF_SCSI_CONTROL_NONSG_IO_CDB\n");
- return -ENOSYS;
- }
- /*
- * For incoming CDBs using a contiguous buffer internal with TCM,
- * save the passed struct scatterlist memory. After TCM storage object
- * processing has completed for this struct se_cmd, TCM core will call
- * transport_memcpy_[write,read]_contig() as necessary from
- * transport_generic_complete_ok() and transport_write_pending() in order
- * to copy the TCM buffer to/from the original passed *mem in SGL ->
- * struct scatterlist format.
- */
- cmd->se_cmd_flags |= SCF_PASSTHROUGH_CONTIG_TO_SG;
- cmd->t_task_pt_sgl = sgl;
- cmd->t_task_pt_sgl_num = sgl_count;
}
return 0;
return 0;
}
+void *transport_kmap_first_data_page(struct se_cmd *cmd)
+{
+ struct se_mem *se_mem;
+
+ BUG_ON(list_empty(&cmd->t_mem_list));
+
+ se_mem = list_first_entry(&cmd->t_mem_list, struct se_mem, se_list);
+
+ /*
+ * 1st se_mem should point to a page, and we shouldn't need more than
+ * that for this cmd
+ */
+ BUG_ON(cmd->data_length > PAGE_SIZE);
+
+ return kmap(se_mem->se_page);
+}
+EXPORT_SYMBOL(transport_kmap_first_data_page);
+
+void transport_kunmap_first_data_page(struct se_cmd *cmd)
+{
+ struct se_mem *se_mem;
+
+ BUG_ON(list_empty(&cmd->t_mem_list));
+
+ se_mem = list_first_entry(&cmd->t_mem_list, struct se_mem, se_list);
+
+ kunmap(se_mem->se_page);
+}
+EXPORT_SYMBOL(transport_kunmap_first_data_page);
+
static int
-transport_generic_get_mem(struct se_cmd *cmd, u32 length)
+transport_generic_get_mem(struct se_cmd *cmd)
{
struct se_mem *se_mem;
+ int length = cmd->data_length;
/*
* If the device uses memory mapping this is enough.
if (cmd->se_dev->transport->do_se_mem_map)
return 0;
+ /* Even cmds with length 0 will get here, btw */
while (length) {
se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
if (!(se_mem)) {
if (dev->transport->map_task_SG)
return dev->transport->map_task_SG(task);
return 0;
- } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
- if (dev->transport->map_task_non_SG)
- return dev->transport->map_task_non_SG(task);
- return 0;
} else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
if (dev->transport->cdb_none)
return dev->transport->cdb_none(task);
* cmd->t_mem_list of struct se_mem->se_page
*/
if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
- ret = transport_allocate_resources(cmd);
+ ret = transport_generic_get_mem(cmd);
if (ret < 0)
return ret;
}
cmd->transport_qf_callback = NULL;
return 0;
}
- /*
- * For the TCM control CDBs using a contiguous buffer, do the memcpy
- * from the passed Linux/SCSI struct scatterlist located at
- * se_cmd->t_task_pt_sgl to the contiguous buffer at
- * se_cmd->t_task_buf.
- */
- if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
- sg_copy_to_buffer(cmd->t_task_pt_sgl,
- cmd->t_task_pt_sgl_num,
- cmd->t_task_buf,
- cmd->data_length);
+
/*
* Clear the se_cmd for WRITE_PENDING status in order to set
* cmd->t_transport_active=0 so that transport_generic_handle_data
caller, cmd, cmd->cdb);
printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
- printk(KERN_INFO "%s: cmd %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n",
+ printk(KERN_INFO "%s: cmd %p se_num %u len %u se_cmd_flags <0x%x>\n",
caller, cmd, se_cmd->t_tasks_se_num,
- se_cmd->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags);
+ se_cmd->data_length, se_cmd->se_cmd_flags);
list_for_each_entry(mem, &se_cmd->t_mem_list, se_list)
printk(KERN_INFO "%s: cmd %p mem %p page %p "
remaining = se_cmd->data_length;
/*
- * Setup to use first mem list entry if any.
+ * Setup to use first mem list entry, unless no data.
*/
- if (se_cmd->t_tasks_se_num) {
+ BUG_ON(remaining && list_empty(&se_cmd->t_mem_list));
+ if (remaining) {
mem = list_first_entry(&se_cmd->t_mem_list,
struct se_mem, se_list);
mem_len = mem->se_len;
mem_off = mem->se_off;
page = mem->se_page;
- } else {
- mem = NULL;
- mem_len = remaining;
- mem_off = 0;
- page = NULL;
}
/* no scatter/gather in skb for odd word length due to fc_seq_send() */
tlen = min(mem_len, frame_len);
if (use_sg) {
- if (!mem) {
- BUG_ON(!se_cmd->t_task_buf);
- page_addr = se_cmd->t_task_buf + mem_off;
- /*
- * In this case, offset is 'offset_in_page' of
- * (t_task_buf + mem_off) instead of 'mem_off'.
- */
- off_in_page = offset_in_page(page_addr);
- page = virt_to_page(page_addr);
- tlen = min(tlen, PAGE_SIZE - off_in_page);
- } else
- off_in_page = mem_off;
+ off_in_page = mem_off;
BUG_ON(!page);
get_page(page);
skb_fill_page_desc(fp_skb(fp),
fp_skb(fp)->data_len += tlen;
fp_skb(fp)->truesize +=
PAGE_SIZE << compound_order(page);
- } else if (mem) {
+ } else {
BUG_ON(!page);
from = kmap_atomic(page + (mem_off >> PAGE_SHIFT),
KM_SOFTIRQ0);
memcpy(to, from, tlen);
kunmap_atomic(page_addr, KM_SOFTIRQ0);
to += tlen;
- } else {
- from = se_cmd->t_task_buf + mem_off;
- memcpy(to, from, tlen);
- to += tlen;
}
mem_off += tlen;
frame_len = se_cmd->data_length - rel_off;
/*
- * Setup to use first mem list entry if any.
+ * Setup to use first mem list entry, unless no data.
*/
- if (se_cmd->t_tasks_se_num) {
+ BUG_ON(frame_len && list_empty(&se_cmd->t_mem_list));
+ if (frame_len) {
mem = list_first_entry(&se_cmd->t_mem_list,
struct se_mem, se_list);
mem_len = mem->se_len;
mem_off = mem->se_off;
page = mem->se_page;
- } else {
- mem = NULL;
- page = NULL;
- mem_off = 0;
- mem_len = frame_len;
}
while (frame_len) {
tlen = min(mem_len, frame_len);
- if (mem) {
- to = kmap_atomic(page + (mem_off >> PAGE_SHIFT),
- KM_SOFTIRQ0);
- page_addr = to;
- to += mem_off & ~PAGE_MASK;
- tlen = min(tlen, (size_t)(PAGE_SIZE -
- (mem_off & ~PAGE_MASK)));
- memcpy(to, from, tlen);
- kunmap_atomic(page_addr, KM_SOFTIRQ0);
- } else {
- to = se_cmd->t_task_buf + mem_off;
- memcpy(to, from, tlen);
- }
+ to = kmap_atomic(page + (mem_off >> PAGE_SHIFT),
+ KM_SOFTIRQ0);
+ page_addr = to;
+ to += mem_off & ~PAGE_MASK;
+ tlen = min(tlen, (size_t)(PAGE_SIZE -
+ (mem_off & ~PAGE_MASK)));
+ memcpy(to, from, tlen);
+ kunmap_atomic(page_addr, KM_SOFTIRQ0);
+
from += tlen;
frame_len -= tlen;
mem_off += tlen;
SCF_EMULATED_TASK_SENSE = 0x00000004,
SCF_SCSI_DATA_SG_IO_CDB = 0x00000008,
SCF_SCSI_CONTROL_SG_IO_CDB = 0x00000010,
- SCF_SCSI_CONTROL_NONSG_IO_CDB = 0x00000020,
SCF_SCSI_NON_DATA_CDB = 0x00000040,
SCF_SCSI_CDB_EXCEPTION = 0x00000080,
SCF_SCSI_RESERVATION_CONFLICT = 0x00000100,
SCF_ALUA_NON_OPTIMIZED = 0x00040000,
SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000,
SCF_UNUSED = 0x00100000,
- SCF_PASSTHROUGH_CONTIG_TO_SG = 0x00200000,
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
SCF_EMULATE_CDB_ASYNC = 0x01000000,
SCF_EMULATE_QUEUE_FULL = 0x02000000,
struct completion transport_lun_fe_stop_comp;
struct completion transport_lun_stop_comp;
struct scatterlist *t_tasks_sg_chained;
- struct scatterlist t_tasks_sg_bounce;
- void *t_task_buf;
+
/*
* Used for pre-registered fabric SGL passthrough WRITE and READ
* with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
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);
extern void transport_free_se_cmd(struct se_cmd *);
extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
extern int transport_generic_handle_cdb(struct se_cmd *);
* For SCF_SCSI_NON_DATA_CDB
*/
int (*cdb_none)(struct se_task *);
- /*
- * For SCF_SCSI_CONTROL_NONSG_IO_CDB
- */
- int (*map_task_non_SG)(struct se_task *);
/*
* For SCF_SCSI_DATA_SG_IO_CDB and SCF_SCSI_CONTROL_SG_IO_CDB
*/