Example #1
0
/*
 * Process isns response, need to verify same transaction id, func_id
 * as the isns command, the isns command is in network byte order,
 * the isns response is in host byte order
 */
static int
process_rsp(isns_pdu_t *cmd, isns_rsp_t *rsp)
{
	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_RSP");
	/*
	 * Process responses:
	 *	-verify sucessful response
	 *	-verify match xid
	 *	-process operating attributes
	 * For DevAttrReg & DevAttrQry and most isns command,
	 * the response func_id is  command_func_id | 0x8000.
	 */
	rsp->status = ntohl(rsp->status);
	if (rsp->status != ISNS_RSP_SUCCESSFUL ||
	    rsp->xid != ntohs(cmd->xid) ||
	    rsp->func_id != (ntohs(cmd->func_id) | 0x8000)) {
		queue_prt(mgmtq, Q_ISNS_DBG,
		    "cmd failed with: status= %d xid= %d %d "\
		    "response attribute %x\n", rsp->status, rsp->xid,\
		    ntohs(cmd->xid), rsp->func_id);
		return (-1);
	}

	return (0);
}
Example #2
0
/*
 * []----
 * | session_validate -- do what the name says
 * |
 * | At this point the connection has processed the login command so that
 * | we have InitiatorName and ISID at a minimum. Check to see if there
 * | are other sessions which match. If so, log that one out and proceed with
 * | this session. If nothing matches, then link this into a global list.
 * |
 * | Once we support multiple connections per session need to scan list
 * | to see if other connection have the same CID. If so, log out that
 * | connection.
 * []----
 */
Boolean_t
session_validate(iscsi_sess_t *s)
{
	iscsi_sess_t	*check;

	queue_prt(s->s_mgmtq, Q_SESS_NONIO,
	    "SES%x  %s ISID[%02x%02x%02x%02x%02x%02x]",
	    s->s_num, s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias,
	    s->s_isid[0], s->s_isid[1], s->s_isid[2],
	    s->s_isid[3], s->s_isid[4], s->s_isid[5]);


	/*
	 * SessionType=Discovery which means no target name and therefore
	 * this is okay.
	 */
	if (s->s_t_name == NULL)
		return (True);

	(void) pthread_mutex_lock(&sess_mutex);
	for (check = sess_head; check; check = check->s_next) {
		/*
		 * Ignore ourselves in this check.
		 */
		if (check == s)
			continue;
		if ((check->s_t_name == NULL) ||
		    (strcmp(check->s_t_name, s->s_t_name) != 0))
			continue;
		if (strcmp(check->s_i_name, s->s_i_name) != 0)
			continue;
		if (check->s_conn_head->c_tpgt != s->s_conn_head->c_tpgt)
			continue;
		/*
		 * Section 5.3.5
		 * Session reinstatement is the process of the initiator
		 * logging in with an ISID that is possible active from
		 * the target's perspective. Thus implicitly logging out
		 * the session that corresponds to the ISID and
		 * reinstating a new iSCSI session in its place (with the
		 * same ISID).
		 */
		if (bcmp(check->s_isid, s->s_isid, 6) == 0) {
			queue_prt(s->s_mgmtq, Q_SESS_NONIO,
			    "SES%x  Implicit shutdown", check->s_num);
			if (check->s_conn_head->c_state == S5_LOGGED_IN)
				conn_state(check->s_conn_head, T8);
			else
				conn_state(check->s_conn_head, T7);
			break;
		}
	}
	(void) pthread_mutex_unlock(&sess_mutex);

	return (True);
}
Example #3
0
/*
 * []----
 * | sbc_cmd_reserve -- Run commands when another I_T_L has a reservation
 * []----
 */
static void
sbc_cmd_reserved(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	scsi_cmd_table_t	*e;

	switch (cdb[0]) {
	case SCMD_TEST_UNIT_READY:
	case SCMD_INQUIRY:
	case SCMD_REPORT_LUNS:
	case SCMD_LOG_SENSE_G1:
	case SCMD_READ_MEDIA_SERIAL:
	case SCMD_REPORT_TARGET_PORT_GROUPS:
	case SCMD_REQUEST_SENSE:
		/*
		 * SPC-2, revision 20, Section 5.5.1 table 10
		 * The specification allows these three commands
		 * to run even through there's a reservation in place.
		 */
		e = &cmd->c_lu->l_cmd_table[cdb[0]];
#ifdef FULL_DEBUG
		queue_prt(mgmtq, Q_STE_IO, "RESERVED: SBC%x  LUN%d Cmd %s\n",
		    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
		    e->cmd_name == NULL ? "(no name)" : e->cmd_name);
#endif
		(*e->cmd_start)(cmd, cdb, cdb_len);
		break;

	default:
		trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT);
	}
}
Example #4
0
File: util.c Project: imp/slist
/*
 * []----
 * | add_targets -- add TargetName and TargetAddress to text argument
 * |
 * | Add targets which this initiator is allowed to see based on
 * | the access_list associated with a target. If a target doesn't
 * | have an access list then let everyone see it.
 * []----
 */
static Boolean_t
add_targets(iscsi_conn_t *c, char **text, int *text_length)
{
	tgt_node_t	*targ		= NULL;
	Boolean_t	rval		= True;
	char		*targ_name	= NULL;

	while ((rval == True) && ((targ = tgt_node_next_child(targets_config,
	    XML_ELEMENT_TARG, targ)) != NULL)) {

		if (check_access(targ, c->c_sess->s_i_name, False) == True) {

			if (tgt_find_value_str(targ, XML_ELEMENT_INAME,
			    &targ_name) == False) {
				rval = False;
				break;
			}
			queue_prt(c->c_mgmtq, Q_CONN_LOGIN,
			    "CON%x    %24s = %s\n", c->c_num, "TargetName",
			    targ_name);

			(void) add_text(text, text_length, "TargetName",
			    targ_name);
			free(targ_name);
			add_target_address(c, text, text_length, targ);
		}
	}
	return (rval);
}
Example #5
0
static int
do_uscsi(t10_cmd_t *cmd, raw_io_t *io, raw_direction_t dir)
{
	struct uscsi_cmd	u;
	uchar_t			sense_buf[128];

	bzero(&u, sizeof (u));
	u.uscsi_cdb	= (caddr_t)io->r_cdb;
	u.uscsi_cdblen	= io->r_cdb_len;
	u.uscsi_bufaddr	= io->r_data;
	u.uscsi_buflen	= io->r_data_len;
	u.uscsi_flags	= ((dir == RawDataToDevice) ? USCSI_WRITE :
	    (dir == RawDataFromDevice) ? USCSI_READ : 0) | USCSI_RQENABLE;
	u.uscsi_rqbuf	= (char *)sense_buf;
	u.uscsi_rqlen	= sizeof (sense_buf);

	if ((ioctl(cmd->c_lu->l_common->l_fd, USCSICMD, &u) == 0) &&
	    (u.uscsi_status == 0)) {
		io->r_status = 0;
		return (0);
	}
	queue_prt(mgmtq, Q_STE_ERRS,
	    "RAW%d  LUN%d USCSICMD errno %d, cmd_status %d, rqstatus %d, "
	    "rqresid %d",
	    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, errno,
	    u.uscsi_status, u.uscsi_rqstatus, u.uscsi_rqresid);

	if ((u.uscsi_rqlen - u.uscsi_rqresid) <
	    sizeof (struct scsi_extended_sense)) {
		queue_prt(mgmtq, Q_STE_ERRS,
		    "RAW%x  LUN%d -- No sense data, got=%d, needed=%d",
		    cmd->c_lu->l_targ->s_targ_num,
		    cmd->c_lu->l_common->l_num,
		    u.uscsi_rqlen - u.uscsi_rqresid,
		    sizeof (struct scsi_extended_sense));
		spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
		io->r_status = STATUS_CHECK;
		return (STATUS_CHECK);
	} else {
		spc_sense_raw(cmd, sense_buf, u.uscsi_rqlen - u.uscsi_rqresid);
		io->r_status = u.uscsi_status;
		return (u.uscsi_status);
	}
}
Example #6
0
/*
 * SCNDereg
 */
static int
isns_scn_dereg(int so, char *node)
{
	isns_pdu_t	*cmd = NULL;
	isns_rsp_t	*rsp = NULL;
	uint32_t	flags = 0;
	int		ret = -1;

	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_DEREG");

	if (isns_create_pdu(ISNS_SCN_DEREG, flags, &cmd) != 0) {
		return (-1);
	}

	/* source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) == -1) {
		goto error;
	}

	/* message key attribute */
	/* iscsi initiator node name */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) != 0) {
		goto error;
	}

	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
		goto error;
	}

	if (isns_send(so, cmd) == -1) {
		syslog(LOG_ERR, "isns_scn_reg fails isns_send");
		goto error;
	}

	if (isns_recv(so, &rsp) == -1) {
		syslog(LOG_ERR, "isns_scn_reg fails isns_recv ");
		goto error;
	}

	/* process response */
	if (process_rsp(cmd, rsp) == 0) {
		ret = 0;
	}

error:
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	return (ret);
}
Example #7
0
/*
 * []----
 * | sbc_cmd -- start a SCSI command
 * |
 * | This routine is called from within the SAM-3 Task router.
 * []----
 */
static void
sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	scsi_cmd_table_t	*e;

	e = &cmd->c_lu->l_cmd_table[cdb[0]];
#ifdef FULL_DEBUG
	queue_prt(mgmtq, Q_STE_IO, "SBC%x  LUN%d Cmd %s\n",
	    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
	    e->cmd_name == NULL ? "(no name)" : e->cmd_name);
#endif
	(*e->cmd_start)(cmd, cdb, cdb_len);
}
Example #8
0
/*
 * []------------------------------------------------------------------[]
 * | SCSI Object-Based Storage Device Commands				|
 * | T10/1355-D								|
 * | The following functions implement the emulation of OSD type	|
 * | commands.								|
 * []------------------------------------------------------------------[]
 */
static void
osd_service_action(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	osd_generic_cdb_t	*o;
	uint16_t		service_action;

	/*
	 * debug only -- no need to drop core if someone doesn't play right.
	 */
	assert(cdb_len == sizeof (*o));
	if (cdb_len != sizeof (*o)) {
		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
		spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, SPC_ASCQ_INVALID_CDB);
		trans_send_complete(cmd, STATUS_CHECK);
		return;
	}
	o = (osd_generic_cdb_t *)cdb;
	service_action = o->ocdb_basic.b_service_action[0] << 8 |
	    o->ocdb_basic.b_service_action[1];

	queue_prt(mgmtq, Q_STE_NONIO,
	    "OSD%x  LUN%d service=0x%x, options=0x%x, specific_opts=0x%x,"
	    " fmt=0x%x", cmd->c_lu->l_targ->s_targ_num,
	    cmd->c_lu->l_common->l_num, service_action, o->ocdb_options,
	    o->ocdb_specific_opts, o->ocdb_fmt);

	switch (service_action) {
	case OSD_APPEND:
	case OSD_CREATE:
	case OSD_CREATE_AND_WRITE:
	case OSD_CREATE_COLLECTION:
	case OSD_CREATE_PARTITION:
	case OSD_FLUSH:
	case OSD_FLUSH_COLLECTION:
	case OSD_FLUSH_OSD:
	case OSD_FLUSH_PARTITION:
	case OSD_FORMAT_OSD:
	case OSD_GET_ATTR:
	case OSD_LIST:
		osd_list(cmd, cdb, cdb_len);
		break;

	case OSD_LIST_COLLECTION:
	case OSD_PERFORM_SCSI:
	case OSD_TASK_MGMT:
	default:
		spc_unsupported(cmd, cdb, cdb_len);
		break;
	}
}
Example #9
0
/*
 * []----
 * | sbc_data -- Data phase for command.
 * |
 * | Normally this is only called for the WRITE command. Other commands
 * | that have a data in phase will probably be short circuited when
 * | we call trans_rqst_dataout() and the data is already available.
 * | At least this is true for iSCSI. FC however will need a DataIn phase
 * | for commands like MODE SELECT and PGROUT.
 * []----
 */
static void
sbc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data,
    size_t data_len)
{
	scsi_cmd_table_t	*e;

	e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]];
#ifdef FULL_DEBUG
	queue_prt(mgmtq, Q_STE_IO, "SBC%x  LUN%d Data %s\n",
	    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
	    e->cmd_name);
#endif
	(*e->cmd_data)(cmd, id, offset, data, data_len);
}
Example #10
0
/*
 * []----
 * | osd_list -- return a list of objects
 * []----
 */
static void
osd_list(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	osd_cmd_list_t		*o	= (osd_cmd_list_t *)cdb;
	osd_obj_id_t		part;
	osd_list_param_t	*data;
	uint64_t		len, alloc_len;

	part = (uint64_t)o->ocdb_partition_id[0] << 56 |
	    (uint64_t)o->ocdb_partition_id[1] << 48 |
	    (uint64_t)o->ocdb_partition_id[2] << 40 |
	    (uint64_t)o->ocdb_partition_id[3] << 32 |
	    (uint64_t)o->ocdb_partition_id[4] << 24 |
	    (uint64_t)o->ocdb_partition_id[5] << 16 |
	    (uint64_t)o->ocdb_partition_id[6] << 8 |
	    (uint64_t)o->ocdb_partition_id[7];
	len = (uint64_t)o->ocdb_length[0] << 56 |
	    (uint64_t)o->ocdb_length[1] << 48 |
	    (uint64_t)o->ocdb_length[2] << 40 |
	    (uint64_t)o->ocdb_length[3] << 32 |
	    (uint64_t)o->ocdb_length[4] << 24 |
	    (uint64_t)o->ocdb_length[5] << 16 |
	    (uint64_t)o->ocdb_length[6] << 8 |
	    (uint64_t)o->ocdb_length[7];

	if (len == 0) {
		trans_send_complete(cmd, STATUS_GOOD);
		return;
	}

	queue_prt(mgmtq, Q_STE_NONIO, "part=0x%llx, len=0x%llx", part, len);
	alloc_len = MAX(sizeof (*data), len);
	if ((data = calloc(1, alloc_len)) == NULL) {
		trans_send_complete(cmd, STATUS_BUSY);
		return;
	}
	data->op_length[7] = sizeof (*data) - 8;
	if (part == OSD_PARTITION_ROOT)
		data->op_root = 1;

	(void) trans_send_datain(cmd, (char *)data, sizeof (*data), 0, free,
	    True, (emul_handle_t)data);
}
Example #11
0
/*
 * []----
 * | session_free -- remove connection from session
 * []----
 */
static void
session_free(iscsi_sess_t *s)
{
	iscsi_sess_t	*n;

	/*
	 * Early errors in connection setup can still call this routine
	 * which means the session hasn't been called.
	 */
	if (s == NULL)
		return;

	if (s->s_i_name)
		free(s->s_i_name);
	if (s->s_t_name)
		free(s->s_t_name);
	if (s->s_i_alias)
		free(s->s_i_alias);

	(void) pthread_mutex_lock(&sess_mutex);
	if (sess_head == s)
		sess_head = s->s_next;
	else {
		for (n = sess_head; n; n = n->s_next) {
			if (n->s_next == s) {
				n->s_next = s->s_next;
				break;
			}
		}
		if (n == NULL) {
			queue_prt(s->s_mgmtq, Q_SESS_ERRS,
			    "SES%x  NOT IN SESSION LIST!", s->s_num);
		}
	}
	(void) pthread_mutex_unlock(&sess_mutex);
}
Example #12
0
/*
 * Register a new node, need to find another node that is already registered
 * DevAttrReg
 * RFC 4171 Section 5.6.5.5 indicated SCN-port-tag (23) needed to be
 * included in the registration
 * Also need to register ESI-port-tag (20) see Section 6.3.5
 */
static int
isns_dev_attr_reg(int so, tgt_node_t *tgt, char *node, char *alias)
{
	isns_pdu_t	*cmd = NULL;
	isns_rsp_t	*rsp = NULL;
	uint32_t	flags = 0;
	int		ret = 0;
	Boolean_t	found = False;
	tgt_node_t	*src = NULL;
	char		*src_nm = NULL;

	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_REG");

	if ((so = isns_open(isns_args.server)) == -1) {
		return (-1);
	}

	if (num_reg == 0) {
		flags |= ISNS_FLAG_REPLACE_REG;
	}

	if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) {
		return (-1);
	}

	if (num_reg == 0) {
		/* add new node to source attribute */
		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
		    STRLEN(node), node, 0) != 0) {
			goto error;
		}
	} else {
		/* find a registered node to use */
		do {
			src = find_next_tgt(src, &src_nm);
			if (src == NULL) {
				syslog(LOG_ALERT, "ISNS out of sync\n");
				goto error;
			}
			if (tgt == src) {
				free(src_nm);
				src_nm = NULL;
				continue;
			} else {
				found = True;
			}
		} while (found == False);

		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
		    STRLEN(src_nm), src_nm, 0) != 0) {
			goto error;
		}
	}

	/* add message key attribute */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* add delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
		goto error;
	}

	/* add operation attributes */

	/* entity id */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* entity type */
	if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID,
	    ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
		goto error;
	}

	/*
	 * Register entity portal properties the 1st time
	 */
	if (num_reg == 0) {
		/* portal ip-addr */
		if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID,
		    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
		    eid_ip.ip_len) != 0) {
			goto error;
		}

		/* portal port */
		if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID,
		    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
			goto error;
		}

		/* ESI interval */
		if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID,
		    ISNS_ESI_TICK_SZ, NULL, 10) != 0) {
			goto error;
		}

		/* scn port */
		if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID,
		    ISNS_PORT_SZ, NULL, scn_port) != 0) {
			goto error;
		}

		/* esi port */
		if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID,
		    ISNS_PORT_SZ, NULL, scn_port) != 0) {
			goto error;
		}
	}

	/* iscsi node name */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) != 0) {
		goto error;
	}

	/* iscsi node type */
	if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
	    ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE) != 0) {
		goto error;
	}

	/* iscsi node alias */
	if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
	    STRLEN(alias), alias, 0) != 0) {
		goto error;
	}

	/* PGT */
	if (append_tpgt(tgt, cmd) != 0) {
		goto error;
	}

	/* send pdu */
	if (isns_send(so, cmd) == -1) {
		goto error;
	}

	/* get isns response */
	if (isns_recv(so, &rsp) == -1) {
		goto error;
	}

	/* process response */
	if ((ret = process_rsp(cmd, rsp)) == 0) {
		num_reg++;
	}

error:
	/* Free all resouces here */
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	if (src_nm)
		free(src_nm);
	return (ret);
}
Example #13
0
/*
 * SCNReg
 * See RFC 4171 Section 5.6.5.5
 */
static int
isns_scn_reg(int so, char *node)
{
	isns_pdu_t	*cmd;
	isns_rsp_t	*rsp;
	uint32_t	flags = 0;
	uint32_t	bitmap = 0;
	int		ret = -1;

	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_REG");

	if (isns_create_pdu(ISNS_SCN_REG, flags, &cmd) != 0) {
		return (-1);
	}

	/* source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) == -1) {
		goto error;
	}

	/* message key attribute */
	/* iscsi initiator node name */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) != 0) {
		goto error;
	}

	/* delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
		goto error;
	}

	/* SCN bitmap */
	bitmap = ISNS_INIT_SELF_INFO_ONLY | ISNS_OBJ_REMOVED |
	    ISNS_OBJ_ADDED | ISNS_OBJ_UPDATED;
	if (isns_append_attr(cmd, ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
	    ISNS_SCN_BITMAP_SZ, NULL, bitmap) == -1) {
		goto error;
	}

	if (isns_send(so, cmd) == -1) {
		syslog(LOG_ERR, "isns_scn_reg fails isns_send");
		goto error;
	}

	if (isns_recv(so, &rsp) == -1) {
		syslog(LOG_ERR, "isns_scn_reg fails isns_recv ");
		goto error;
	}

	/* process response */
	if (process_rsp(cmd, rsp) == 0) {
		ret = 0;
	}

error:
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	return (ret);
}
Example #14
0
/*
 * []----
 * | sess_process -- handle messages from the connection(s)
 * []----
 */
static void *
sess_process(void *v)
{
	iscsi_sess_t	*s = (iscsi_sess_t *)v;
	iscsi_conn_t	*c;
	iscsi_cmd_t	*cmd;
	msg_t		*m;
	Boolean_t	process = True;
	mgmt_request_t	*mgmt;
	name_request_t	*nr;
	t10_cmd_t	*t10_cmd;
	char		**buf,
			local_buf[16];
	int		lun;
	extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer);

	(void) pthread_mutex_lock(&s->s_mutex);
	s->s_state = SS_RUNNING;
	(void) pthread_mutex_unlock(&s->s_mutex);
	do {
		m = queue_message_get(s->s_sessq);
		switch (m->msg_type) {
		case msg_cmd_send:
			cmd = (iscsi_cmd_t *)m->msg_data;
			if (s->s_t10 == NULL) {

				/*
				 * The value of 0x960 comes from T10.
				 * See SPC-4, revision 1a, section 6.4.2,
				 * table 87
				 *
				 * XXX Need to rethink how I should do
				 * the callback.
				 */
				s->s_t10 = t10_handle_create(s->s_t_name,
				    T10_TRANS_ISCSI, s->s_conn_head->c_tpgt,
				    s->s_conn_head->c_max_burst_len,
				    s->s_t10q, dataout_callback);
			}
			if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb,
			    cmd->c_scb_len, (transport_t)cmd,
			    &t10_cmd) == False) {

				queue_prt(s->s_mgmtq, Q_SESS_ERRS,
				    "SES%x  FAILED to create cmd", s->s_num);
				/*
				 * If the command create failed, the T10 layer
				 * will attempt to create a sense buffer
				 * telling the initiator what went wrong. If
				 * that layer was unable to accomplish that
				 * things are really bad and we need to just
				 * close the connection.
				 */
				if (cmd->c_t10_cmd != NULL) {
					queue_message_set(
					    cmd->c_allegiance->c_dataq,
					    0, msg_cmd_cmplt, t10_cmd);
				} else
					conn_state(cmd->c_allegiance, T11);
			} else {
				(void) pthread_mutex_lock(
				    &cmd->c_allegiance->c_mutex);
				if (cmd->c_state != CmdCanceled) {
					cmd->c_t10_cmd = t10_cmd;
					(void) t10_cmd_send(s->s_t10,
					    cmd->c_t10_cmd, cmd->c_data,
					    cmd->c_data_len);
				} else {
					t10_cmd_state(t10_cmd,
					    T10_Cmd_Event_Canceled);
				}
				(void) pthread_mutex_unlock(
				    &cmd->c_allegiance->c_mutex);
			}
			break;

		case msg_cmd_data_out:
			cmd = (iscsi_cmd_t *)m->msg_data;
			if (s->s_t10 != NULL)
				(void) t10_cmd_data(s->s_t10, cmd->c_t10_cmd,
				    cmd->c_offset_out, cmd->c_data,
				    cmd->c_data_len);
			break;

		case msg_targ_inventory_change:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, InventoryChange,
				    0, 0);
			break;

		case msg_lu_capacity_change:
			lun = (int)(uintptr_t)m->msg_data;
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, CapacityChange,
				    lun, 0);
			break;

		case msg_reset_targ:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, ResetTarget,
				    0, 0);
			break;

		case msg_reset_lu:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, ResetLun,
				    (int)(uintptr_t)m->msg_data, 0);
			break;

		case msg_shutdown:
			(void) pthread_mutex_lock(&s->s_mutex);
			s->s_state = SS_SHUTDOWN_START;
			(void) pthread_mutex_unlock(&s->s_mutex);

			/*
			 * Shutdown rquest comming from a connection. Only
			 * shutdown the STE if this is the last connection
			 * for this session.
			 */
			c = (iscsi_conn_t *)m->msg_data;
			if (session_remove_connection(s, c) == True) {
				queue_prt(s->s_mgmtq, Q_SESS_NONIO,
				    "SES%x  Starting shutdown", s->s_num);

				/*
				 * If this is the last connection for this
				 * session send a message to the SAM-3 layer to
				 * shutdown.
				 */
				if (s->s_t10 != NULL) {
					t10_handle_disable(s->s_t10);
				}
				queue_message_set(s->s_t10q, 0,
				    msg_shutdown_rsp, 0);
				process = False;
			} else {

				/*
				 * Since this isn't the last connection for
				 * the session, acknowledge the connection
				 * request now since it's references from
				 * this session have been removed.
				 */
				queue_message_set(c->c_dataq, 0,
				    msg_shutdown_rsp, (void *)False);
			}
			break;

		case msg_initiator_name:
			nr = (name_request_t *)m->msg_data;
			s->s_i_name = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_initiator_name, 0);
			break;

		case msg_initiator_alias:
			nr = (name_request_t *)m->msg_data;
			s->s_i_alias = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_initiator_alias, 0);
			break;

		case msg_target_name:
			nr = (name_request_t *)m->msg_data;
			s->s_t_name = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_target_name, 0);
			break;

		case msg_mgmt_rqst:
			mgmt		= (mgmt_request_t *)m->msg_data;
			m->msg_data	= NULL;

			(void) pthread_mutex_lock(&mgmt->m_resp_mutex);
			buf = mgmt->m_u.m_resp;

			if ((s->s_type == SessionNormal) &&
			    (mgmt->m_request == mgmt_full_phase_statistics) &&
			    (strcmp(s->s_t_name, mgmt->m_targ_name) == 0)) {

				buf_add_tag(buf, XML_ELEMENT_CONN, Tag_Start);
				buf_add_tag(buf, s->s_i_name, Tag_String);
				if (s->s_i_alias != NULL) {
					xml_add_tag(buf, XML_ELEMENT_ALIAS,
					    s->s_i_alias);
				}

				/*
				 * Need to loop through the connections
				 * and create one time_connected tag for
				 * each. This will be needed once MC/S support
				 * is added.
				 */
				(void) snprintf(local_buf, sizeof (local_buf),
				    "%d",
				    mgmt->m_time - s->s_conn_head->c_up_at);
				xml_add_tag(buf, XML_ELEMENT_TIMECON,
				    local_buf);

				buf_add_tag(buf, XML_ELEMENT_STATS, Tag_Start);

				t10_targ_stat(s->s_t10, buf);

				buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End);
				buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End);
			}

			(void) pthread_mutex_unlock(&mgmt->m_resp_mutex);

			queue_message_set(mgmt->m_q, 0, msg_mgmt_rply, 0);

			break;

		default:
			queue_prt(s->s_mgmtq, Q_SESS_ERRS,
			    "SES%x  Unknown msg type (%d) from Connection",
			    s->s_num, m->msg_type);
			break;
		}
		queue_message_free(m);
	} while (process == True);

	return (NULL);
}
Example #15
0
/*
 * []----
 * | sess_from_t10 -- handle messages from the T10 layer
 * []----
 */
void *
sess_from_t10(void *v)
{
	iscsi_sess_t	*s	= (iscsi_sess_t *)v;
	msg_t		*m;
	Boolean_t	process	= True;

	while (process == True) {
		m = queue_message_get(s->s_t10q);
		switch (m->msg_type) {
			case msg_cmd_data_rqst:
				queue_message_set(s->s_conn_head->c_dataq, 0,
				    msg_cmd_data_rqst, m->msg_data);
				break;

			case msg_cmd_data_in:
				queue_message_set(s->s_conn_head->c_dataq, 0,
				    msg_cmd_data_in, m->msg_data);
				break;

			case msg_cmd_cmplt:
				queue_message_set(s->s_conn_head->c_dataq, 0,
				    msg_cmd_cmplt, m->msg_data);
				break;

			case msg_shutdown_rsp:

				if (s->s_t10) {
					t10_handle_destroy(s->s_t10);
					s->s_t10 = NULL;
				}

				(void) pthread_mutex_lock(&s->s_mutex);
				s->s_state = SS_SHUTDOWN_CMPLT;
				(void) pthread_mutex_unlock(&s->s_mutex);

				session_free(s);

				/*
				 * Let the connection, which is the last, know
				 * about our completion of the shutdown.
				 */
				queue_message_set(s->s_conn_head->c_dataq, 0,
				    msg_shutdown_rsp, (void *)True);
				process		= False;
				s->s_state	= SS_FREE;
				break;

			default:
				queue_prt(s->s_mgmtq, Q_SESS_ERRS,
				    "SES%x  Unknown msg type (%d) from T10 ",
				    s->s_num, m->msg_type);
				queue_message_set(s->s_conn_head->c_dataq, 0,
				    m->msg_type, m->msg_data);
				break;
		}
		queue_message_free(m);
	}
	queue_free(s->s_t10q, NULL);
	util_title(s->s_mgmtq, Q_SESS_LOGIN, s->s_num, "End Session");
	free(s);
	return (NULL);
}
Example #16
0
File: util.c Project: imp/slist
/*
 * []----
 * | parse_text -- receive text information from initiator and parse
 * |
 * | Read in the current data based on the amount which the login PDU says
 * | should be available. Add it to the end of previous data if it exists.
 * | Previous data would be from a PDU which had the 'C' bit set and was
 * | stored in the connection.
 * |
 * | Once values for parameter name has been selected store outgoing string
 * | in text message for response.
 * |
 * | If errcode is non-NULL the appropriate login error code will be
 * | stored.
 * []----
 */
Boolean_t
parse_text(iscsi_conn_t *c, int dlen, char **text, int *text_length,
    int *errcode)
{
	char		*p		= NULL;
	char		*n;
	char		*cur_pair;
	char		param_rsp[32];
	int		plen;		/* pair length */
	Boolean_t	rval		= True;
	char		*target_name    = NULL;
	char		*initiator_name = NULL;
	char		param_buf[16];

	if ((p = (char *)malloc(dlen)) == NULL)
		return (False);

	/*
	 * Read in data to buffer.
	 */
	if (read(c->c_fd, p, dlen) != dlen) {
		free(p);
		return (False);
	}

	queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x  Available text size %d\n",
	    c->c_num, dlen);

	/*
	 * Read in and toss any pad data
	 */
	if (dlen % ISCSI_PAD_WORD_LEN) {
		char junk[ISCSI_PAD_WORD_LEN];
		int pad_len = ISCSI_PAD_WORD_LEN - (dlen % ISCSI_PAD_WORD_LEN);

		if (read(c->c_fd, junk, pad_len) != pad_len) {
			free(p);
			return (False);
		}
	}

	if (c->c_text_area != NULL) {
		if ((n = (char *)realloc(c->c_text_area,
		    c->c_text_len + dlen)) == NULL) {
			free(p);
			return (False);
		}
		bcopy(p, n + c->c_text_len, dlen);

		/*
		 * No longer need the space allocated to 'p' since it
		 * will point to the aggregated area of all data.
		 */
		free(p);

		/*
		 * Point 'p' to this new area for parsing and save the
		 * combined length in dlen.
		 */
		p = n;
		dlen += c->c_text_len;

		/*
		 * Clear the indication that space has been allocated
		 */
		c->c_text_area = NULL;
		c->c_text_len = 0;
	}

	/*
	 * At this point 'p' points to the name/value parameters. Need
	 * to cycle through each pair.
	 */
	n = p;
	while (dlen > 0) {
		cur_pair = n;

		plen = strlen(n);
		if ((n = strchr(cur_pair, ISCSI_TEXT_SEPARATOR)) == NULL) {
			if (errcode != NULL)
				*errcode =
				    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
				    ISCSI_LOGIN_STATUS_INIT_ERR;
			rval = False;
			break;
		} else
			*n++ = '\0';

		queue_prt(c->c_mgmtq, Q_CONN_LOGIN, "CON%x    %-24s = %s\n",
		    c->c_num, cur_pair, n);

		/*
		 * At this point, 'cur_pair' points at the name and 'n'
		 * points at the value.
		 */

		/*
		 * []--------------------------------------------------[]
		 * | The order of parameters processed matches the	|
		 * | the RFC in section 12.				|
		 * []--------------------------------------------------[]
		 */
		/*
		 * 12.1 -- HeaderDigest
		 * Negotiated
		 */
		if (strcmp("HeaderDigest", cur_pair) == 0) {

			rval = parse_digest_vals(&c->c_header_digest,
			    cur_pair, n, text, text_length);

		/*
		 * 12.1 -- DataDigest
		 * Negotiated
		 */
		} else if (strcmp("DataDigest", cur_pair) == 0) {

			rval = parse_digest_vals(&c->c_data_digest, cur_pair,
			    n, text, text_length);

		/*
		 * 12.2 -- MaxConnections
		 * Negotiated
		 */
		} else if (strcmp("MaxConnections", cur_pair) == 0) {

			/* ---- To be fixed ---- */
			c->c_max_connections = 1;
			(void) snprintf(param_rsp, sizeof (param_rsp),
			    "%d", c->c_max_connections);
			rval = add_text(text, text_length,
			    cur_pair, param_rsp);

		/*
		 * 12.3 -- SendTargets
		 * Declarative
		 */
		} else if (strcmp("SendTargets", cur_pair) == 0) {

			if ((c->c_sess->s_type != SessionDiscovery) &&
			    (strcmp("All", n) == 0)) {
				rval = add_text(text, text_length, cur_pair,
				    "Irrelevant");
			} else {
				rval = add_targets(c, text, text_length);
			}

		/*
		 * 12.4 -- TargetName
		 * Declarative
		 */
		} else if (strcmp("TargetName", cur_pair) == 0) {

			send_named_msg(c, msg_target_name, n);
			target_name = n;

		/*
		 * 12.5 -- IntiatorName
		 * Declarative
		 */
		} else if (strcmp("InitiatorName", cur_pair) == 0) {

			send_named_msg(c, msg_initiator_name, n);
			initiator_name = n;

		/* ---- Section 12.6 is handled within TargetName ---- */

		/*
		 * 12.7 -- InitiatorAlias
		 * Declarative
		 */
		} else if (strcmp("InitiatorAlias", cur_pair) == 0) {

			send_named_msg(c, msg_initiator_alias, n);

		/*
		 * Sections 12.8 (TargetAddress) and 12.9
		 * (TargetPortalGroupTag) are handled during the SendTargets
		 * processing.
		 */

		/*
		 * 12.10 -- IntialR2T
		 * Negotiated
		 */
		} else if (strcmp("InitialR2T", cur_pair) == 0) {

			c->c_initialR2T = True;
			rval = add_text(text, text_length, cur_pair, "Yes");

		/*
		 * 12.11 -- ImmediateData
		 * Negotiated
		 */
		} else if (strcmp("ImmediateData", cur_pair) == 0) {

			/*
			 * Since we can handle immediate data without
			 * a problem just echo back what the initiator
			 * sends. If the initiator decides to violate
			 * the spec by sending immediate data even though
			 * they've disabled it, it's their problem and
			 * we'll deal with the data.
			 */
			c->c_immediate_data = strcmp(n, "No") ? True : False;
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.12 -- MaxRecvDataSegmentLength
		 * Declarative
		 */
		} else if (strcmp("MaxRecvDataSegmentLength", cur_pair) == 0) {

			c->c_max_recv_data = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.13 -- MaxBurstLength
		 * Negotiated
		 */
		} else if (strcmp("MaxBurstLength", cur_pair) == 0) {

			c->c_max_burst_len = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.14 -- FirstBurstLength
		 * Negotiated
		 */
		} else if (strcmp("FirstBurstLength", cur_pair) == 0) {

			/*
			 * We can handle anything the initiator wishes
			 * to shove in our direction. So, store the value
			 * in case we ever wish to validate input data,
			 * but there's no real need to do so.
			 */
			c->c_first_burst_len = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.15 DefaultTime2Wait
		 * Negotiated
		 */
		} else if (strcmp("DefaultTime2Wait", cur_pair) == 0) {

			c->c_default_time_2_wait = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.16 -- DefaultTime2Retain
		 * Negotiated
		 */
		} else if (strcmp("DefaultTime2Retain", cur_pair) == 0) {

			c->c_default_time_2_retain = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.17 -- MaxOutstandingR2T
		 * Negotiated
		 */
		} else if (strcmp("MaxOutstandingR2T", cur_pair) == 0) {

			/*
			 * Save the value, but at most we'll toss out
			 * one R2T packet.
			 */
			c->c_max_outstanding_r2t = strtol(n, NULL, 0);
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.18 -- DataPDUInOder
		 * Negotiated
		 */
		} else if (strcmp("DataPDUInOrder", cur_pair) == 0) {

			/*
			 * We can handle DataPDU's out of order and
			 * currently we'll only send them in order. We're
			 * to far removed from the hardware to see data
			 * coming off of the platters out of order so
			 * it's unlikely we'd ever implement this feature.
			 * Store the parameter and echo back the initiators
			 * request.
			 */
			c->c_data_pdu_in_order = strcmp(n, "Yes") == 0 ?
			    True : False;
			rval = add_text(text, text_length, cur_pair, n);

		/*
		 * 12.19 -- DataSequenceInOrder
		 * Negotiated
		 */
		} else if (strcmp("DataSequenceInOrder", cur_pair) == 0) {

			/*
			 * Currently we're set up to look at and require
			 * PDU sequence numbers be in order. The check
			 * now is only done as a prelude to supporting
			 * MC/S and guaranteeing the order of incoming
			 * packets on different connections.
			 */
			c->c_data_sequence_in_order = True;
			rval = add_text(text, text_length, cur_pair, "Yes");

		/*
		 * 12.20 -- ErrorRecoveryLevel
		 * Negotiated
		 */
		} else if (strcmp("ErrorRecoveryLevel", cur_pair) == 0) {

			c->c_erl = 0;
			(void) snprintf(param_rsp, sizeof (param_rsp),
			    "%d", c->c_erl);
			rval = add_text(text, text_length,
			    cur_pair, param_rsp);

		/*
		 * 12.21 -- SessionType
		 * Declarative
		 */
		} else if (strcmp("SessionType", cur_pair) == 0) {

			c->c_sess->s_type = strcmp(n, "Discovery") == 0 ?
			    SessionDiscovery : SessionNormal;


		/*
		 * Appendix A 3.1 -- IFMarker
		 * Negotiated
		 */
		} else if (strcmp("IFMarker", cur_pair) == 0) {

			c->c_ifmarker = False;
			rval = add_text(text, text_length, cur_pair, "No");

		/*
		 * Appendix A 3.1 -- OFMarker
		 * Negotiated
		 */
		} else if (strcmp("OFMarker", cur_pair) == 0) {

			c->c_ofmarker = False;
			rval = add_text(text, text_length, cur_pair, "No");

		} else if ((strcmp("AuthMethod", cur_pair) == 0) ||
		    (strcmp("CHAP_A", cur_pair) == 0) ||
		    (strcmp("CHAP_I", cur_pair) == 0) ||
		    (strcmp("CHAP_C", cur_pair) == 0) ||
		    (strcmp("CHAP_N", cur_pair) == 0) ||
		    (strcmp("CHAP_R", cur_pair) == 0)) {

			rval = add_text(&(c->auth_text), &c->auth_text_length,
			    cur_pair, n);

		} else {

			/*
			 * It's perfectly legitimate for an initiator to
			 * send us a parameter we don't currently understand.
			 * For example, an initiator that supports iSER will
			 * send an RDMA options parameter. If we respond with
			 * a valid return value it knows to switch to iSER
			 * for future processing.
			 */
			rval = add_text(text, text_length,
			    cur_pair, "NotUnderstood");

			/*
			 * Go ahead a log this information in case we see
			 * something unexpected.
			 */
			queue_prt(c->c_mgmtq, Q_CONN_ERRS,
			    "CON%x  Unknown parameter %s=%s\n",
			    c->c_num, cur_pair, n);
		}

		/*
		 * If parsed both Initiator and Target names have been parsed,
		 * then it is now time to load the connection parameters.
		 *
		 * This may fail because the target doesn't exist or the
		 * initiator doesn't have permission to access this target.
		 */
		if ((target_name != NULL) && (initiator_name != NULL)) {
			if ((rval = connection_parameters_get(c, target_name))
			    == False) {
				if ((errcode != NULL) && (*errcode == 0))
					*errcode =
					    (ISCSI_STATUS_CLASS_INITIATOR_ERR
					    << 8) |
					    ISCSI_LOGIN_STATUS_TGT_FORBIDDEN;
			} else if ((rval = add_text(text, text_length,
			    "TargetAlias", c->c_targ_alias)) == True) {

				/*
				 * Add TPGT now
				 */
				(void) snprintf(param_buf, sizeof (param_buf),
				    "%d", c->c_tpgt);
				rval = add_text(text, text_length,
				    "TargetPortalGroupTag", param_buf);
				target_name = initiator_name = NULL;
			}
		}

		if (rval == False) {
			/*
			 * Make sure the caller wants error status and that it
			 * hasn't already been set.
			 */
			if ((errcode != NULL) && (*errcode == 0))
				*errcode =
				    (ISCSI_STATUS_CLASS_TARGET_ERR << 8) |
				    ISCSI_LOGIN_STATUS_TARGET_ERROR;
			break;
		}

		/*
		 * next pair of parameters. 1 is added to include the NULL
		 * byte and the end of each string.
		 */
		n = cur_pair + plen + 1;
		dlen -= (plen + 1);
	}

	if (p != NULL)
		free(p);

	return (rval);
}
Example #17
0
/*
 * Register all iscsi target nodes from the XML database
 * Alway use the ISNS_FLAG_REPLACE_REG flag
 */
int
isns_reg_all()
{
	int so;
	uint32_t	flags = ISNS_FLAG_REPLACE_REG;
	isns_pdu_t	*cmd = NULL;
	isns_rsp_t	*rsp = NULL;
	char		*n = NULL;
	char		*a = NULL;
	char		alias[MAXNAMELEN];
	char		iname[MAXNAMELEN];
	tgt_node_t	*tgt = NULL;
	int		ret = -1;
	int		tgt_cnt = 0;

	if (isns_server_connection_thr_running == False) {
		syslog(LOG_ERR,
		    "isns_reg_all: iSNS discovery is not running."
		    " Check the previous iSNS initialization error.");
		return (-1);
	}

	/*
	 * get the 1st target and use it for the source attribute
	 */
	if ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt))
	    == NULL) {
		return (0);
	}
	if (tgt->x_value == NULL) {
		syslog(LOG_ALERT, "ISNS: target with NULL local name\n");
		return (-1);
	}
	if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
	    == FALSE) {
		syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n");
		return (-1);
	}
	(void) strcpy(iname, n);
	free(n);
	if ((so = isns_open(isns_args.server)) == -1) {
		syslog(LOG_ALERT, "ISNS: fails to connect to %s\n",
		    isns_args.server);
		return (-1);
	}

	if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) {
		goto error;
	}

	/* source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(iname), iname, 0) != 0) {
		goto error;
	}

	/* add message key attribute */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* add delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
		goto error;
	}

	/* entity id */
	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
		goto error;
	}

	/* entity type */
	if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID,
	    ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
		goto error;
	}

	/* portal ip-addr */
	if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID,
	    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
	    eid_ip.ip_len) != 0) {
		goto error;
	}

	/* portal port */
	if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
		goto error;
	}

	/* ESI interval */
	if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID,
	    ISNS_ESI_TICK_SZ, NULL, 10) != 0) {
		goto error;
	}


	/* scn port */
	if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
		goto error;
	}

	/* esi port */
	if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID,
	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
		goto error;
	}

	/*
	 * Open targets_config and devAttrReg all nodes
	 */
	tgt = NULL;
	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
	    tgt)) != NULL) {
		if (tgt->x_value == NULL) {
			syslog(LOG_ALERT, "ISNS: target with NULL name\n");
			continue;
		}
		/* use this value as alias if alias is not set */
		(void) strcpy(alias, tgt->x_value);

		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
		    == FALSE) {
			continue;
		}
		(void) strcpy(iname, n);
		free(n);

		/* find alias */
		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a)
		    == TRUE) {
			(void) strcpy(alias, a);
			free(a);
		}

		tgt_cnt++;		/* increment target count */

		/* operation attributes */
		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
		    STRLEN(iname), iname, 0) != 0) {
			goto error;
		}
		if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
		    4, NULL, ISNS_TARGET_NODE_TYPE) != 0) {
			goto error;
		}
		if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
		    STRLEN(alias), alias, 0) != 0) {
			goto error;
		}

		if (append_tpgt(tgt, cmd) != 0) {
			goto error;
		}

	}

	/* send pdu */
	if (isns_send(so, cmd) == -1) {
		goto error;
	}

	/* get isns response */
	if (isns_recv(so, &rsp) == -1) {
		goto error;
	}

	/* process response */
	if (process_rsp(cmd, rsp) == 0) {
		ret = 0;
		num_reg = tgt_cnt;
		queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful");
	} else {
		syslog(LOG_ALERT, "DevAttrReg failed");
	}

error:
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	isns_close(so);
	return (ret);
}
Example #18
0
void *
port_watcher(void *v)
{
	int			s,
				fd,
				on = 1;
	char			debug[80];
	struct sockaddr_in	sin_ip;
	struct sockaddr_in6	sin6_ip;
	struct sockaddr_storage	st;
	socklen_t		socklen;
	iscsi_conn_t		*conn;
	port_args_t		*p = (port_args_t *)v;
	target_queue_t		*q = p->port_mgmtq;
	int			l,
				accept_err_sleep = 1;
	pthread_t		junk;
	struct in_addr		addr;
	struct in6_addr		addr6;

	/*
	 * Try creating an IPv6 socket first
	 * If failed, try creating an IPv4 socket
	 */
	if ((s = socket(PF_INET6, SOCK_STREAM, 0)) == -1) {

		queue_str(q, Q_GEN_ERRS, msg_log, "Opening IPv4 socket");
		if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
			queue_str(q, Q_GEN_ERRS, msg_log,
			    "Can't open socket");
			return (NULL);
		} else {
			bzero(&sin_ip, sizeof (sin_ip));
			sin_ip.sin_family = AF_INET;
			sin_ip.sin_port = htons(p->port_num);
			sin_ip.sin_addr.s_addr = INADDR_ANY;

			(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
			    (char *)&on, sizeof (on));

			if ((bind(s, (struct sockaddr *)&sin_ip,
				sizeof (sin_ip))) < 0) {
				(void) snprintf(debug, sizeof (debug),
				    "bind on port %d failed, errno %d",
				    p->port_num, errno);
				queue_str(q, Q_GEN_ERRS, msg_status, debug);
				return (NULL);
			}
		}

	} else {

		queue_str(q, Q_GEN_DETAILS, msg_log, "Got IPv6 socket");
		bzero(&sin6_ip, sizeof (sin6_ip));
		sin6_ip.sin6_family = AF_INET6;
		sin6_ip.sin6_port = htons(p->port_num);
		sin6_ip.sin6_addr = in6addr_any;

		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
		    sizeof (on));

		if ((bind(s, (struct sockaddr *)&sin6_ip, sizeof (sin6_ip)))
		    < 0) {
			(void) snprintf(debug, sizeof (debug),
			    "bind on port %d failed, errno %d",
			    p->port_num, errno);
			queue_str(q, Q_GEN_ERRS, msg_status, debug);
			return (NULL);
		}
	}

	if (listen(s, 5) < 0) {
		queue_str(q, Q_GEN_ERRS, msg_status, "listen failed");
		return (NULL);
	}

	/*CONSTANTCONDITION*/
	while (1) {

		socklen = sizeof (st);
		if ((fd = accept(s, (struct sockaddr *)&st,
		    &socklen)) < 0) {
			accept_err_sleep *= 2;
			(void) sleep(accept_err_sleep);
			if (accept_err_sleep > 60) {
				accept_err_sleep = 1;
				queue_prt(q, Q_GEN_ERRS,
				    "accept failed, errno %d", errno);
			}
			continue;
		}

		l = 128 * 1024;
		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&l,
		    sizeof (l)) < 0)
			queue_str(q, Q_GEN_ERRS, msg_status,
			    "setsockopt failed");
		if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&l,
		    sizeof (l)) < 0)
			queue_str(q, Q_GEN_ERRS, msg_status,
			    "setsockopt failed");
		l = 1;
		if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&l,
		    sizeof (l)) < 0)
			queue_str(q, Q_GEN_ERRS, msg_status,
			    "setsockopt keepalive failed");

		if ((conn = (iscsi_conn_t *)calloc(sizeof (iscsi_conn_t),
		    1)) == NULL) {
			/*
			 * If we fail to get memory this is all rather
			 * pointless, since it's unlikely that queue_str
			 * could malloc memory to send a message.
			 */
			queue_str(q, Q_GEN_ERRS, msg_status,
			    "connection malloc failed");
			return (NULL);
		}

		/*
		 * Save initiator sockaddr for future use
		 */
		conn->c_initiator_sockaddr = st;

		socklen = sizeof (st);
		if (getsockname(fd, (struct sockaddr *)&st,
		    &socklen) == 0) {
			/*
			 * Save target sockaddr for future use
			 */

			addr6 = ((struct sockaddr_in6 *)&st)->sin6_addr;
			if (st.ss_family == AF_INET6 &&
			    IN6_IS_ADDR_V4MAPPED(&addr6)) {
				/*
				 * If target address is IPv4 mapped IPv6 address
				 * convert it to IPv4 address
				 */
				IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
				((struct sockaddr_in *)&st)->sin_addr = addr;
				st.ss_family = AF_INET;
			}

			conn->c_target_sockaddr = st;
		}

		conn->c_fd	= fd;
		conn->c_mgmtq	= q;
		conn->c_up_at	= time(NULL);
		conn->c_state	= S1_FREE;
		(void) pthread_mutex_init(&conn->c_mutex, NULL);
		(void) pthread_mutex_init(&conn->c_state_mutex, NULL);
		(void) pthread_mutex_lock(&port_mutex);
		conn->c_num	= port_conn_num++;
		if (conn_head == NULL) {
			conn_head = conn;
			assert(conn_tail == NULL);
			conn_tail = conn;
		} else {
			conn_tail->c_next = conn;
			conn->c_prev = conn_tail;
			conn_tail = conn;
		}
		(void) pthread_mutex_unlock(&port_mutex);

		(void) pthread_create(&junk, NULL, conn_process, conn);
	}
	return (NULL);
}
Example #19
0
/*ARGSUSED*/
void
sbc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	struct mode_header	*mode_hdr;
	char			*np;
	disk_params_t		*d;
	disk_io_t		*io;

	if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL)
		return;

	/*
	 * SPC-3 Revision 21c section 6.8
	 * Reserve bit checks
	 */
	if ((cdb[1] & ~SPC_MODE_SENSE_DBD) ||
	    SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
		spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
		trans_send_complete(cmd, STATUS_CHECK);
		return;
	}

	/*
	 * Zero length causes a simple ack to occur.
	 */
	if (cdb[4] == 0) {
		trans_send_complete(cmd, STATUS_GOOD);
		return;
	}

	io = sbc_io_alloc(cmd);

	/*
	 * Make sure that we have enough room in the data buffer. We'll
	 * only send back the amount requested though
	 */
	io->da_data_len = MAX(cdb[4], sizeof (struct mode_format) +
	    sizeof (struct mode_geometry) +
	    sizeof (struct mode_control_scsi3) +
	    sizeof (struct mode_cache_scsi3) +
	    sizeof (struct mode_info_ctrl) + (MODE_BLK_DESC_LENGTH * 5));
	if ((io->da_data = (char *)calloc(1, io->da_data_len)) == NULL) {
		sbc_io_free(io);
		trans_send_complete(cmd, STATUS_BUSY);
		return;
	}
	io->da_clear_overlap	= False;
	io->da_data_alloc	= True;
	mode_hdr		= (struct mode_header *)io->da_data;

	switch (cdb[2]) {
	case MODE_SENSE_PAGE3_CODE:
		if ((d->d_heads == 0) && (d->d_cyl == 0) && (d->d_spt == 0)) {
			sbc_io_free(io);
			spc_unsupported(cmd, cdb, cdb_len);
			return;
		}
		mode_hdr->length	= sizeof (struct mode_format);
		mode_hdr->bdesc_length	= MODE_BLK_DESC_LENGTH;
		(void) sense_page3(d,
		    io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length);

		break;

	case MODE_SENSE_PAGE4_CODE:
		if ((d->d_heads == 0) && (d->d_cyl == 0) && (d->d_spt == 0)) {
			sbc_io_free(io);
			spc_unsupported(cmd, cdb, cdb_len);
			return;
		}
		mode_hdr->length	= sizeof (struct mode_geometry);
		mode_hdr->bdesc_length	= MODE_BLK_DESC_LENGTH;
		(void) sense_page4(d,
		    io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length);
		break;

	case MODE_SENSE_CACHE:
		mode_hdr->length	= sizeof (struct mode_cache_scsi3);
		mode_hdr->bdesc_length	= MODE_BLK_DESC_LENGTH;
		(void) sense_cache(d,
		    io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length);
		break;

	case MODE_SENSE_CONTROL:
		mode_hdr->length	= sizeof (struct mode_control_scsi3);
		mode_hdr->bdesc_length	= MODE_BLK_DESC_LENGTH;
		(void) sense_mode_control(cmd->c_lu,
		    io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length);
		break;

	case MODE_SENSE_INFO_CTRL:
		(void) sense_info_ctrl(io->da_data);
		break;

	case MODE_SENSE_SEND_ALL:
		/*
		 * SPC-3 revision 21c
		 * Section 6.9.1 Table 97
		 * "Return all subpage 00h mode pages in page_0 format"
		 */
		if (io->da_data_len < (sizeof (struct mode_format) +
		    sizeof (struct mode_geometry) +
		    sizeof (struct mode_control_scsi3) +
		    sizeof (struct mode_info_ctrl))) {

			/*
			 * Believe it or not, there's an initiator out
			 * there which sends a mode sense request for all
			 * of the pages, without always sending a data-in
			 * size which is large enough.
			 * NOTE: Need to check the error key returned
			 * here and see if something else should be used.
			 */
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			trans_send_complete(cmd, STATUS_CHECK);

		} else {

			/*
			 * If we don't have geometry then don't attempt
			 * report that information.
			 */
			if (d->d_heads && d->d_cyl && d->d_spt) {
				np = sense_page3(d, io->da_data);
				np = sense_page4(d, np);
			}
			np = sense_cache(d, np);
			np = sense_mode_control(cmd->c_lu, np);
			(void) sense_info_ctrl(np);

		}
		break;

	case 0x00:
		/*
		 * SPC-3 Revision 21c, section 6.9.1
		 * Table 97 -- Mode page code usage for all devices
		 * Page Code 00 == Vendor specific. We are going to return
		 *    zeros.
		 */
		break;

	default:
		queue_prt(mgmtq, Q_STE_ERRS,
		    "SBC%x  LUN%d Unsupported mode_sense request 0x%x",
		    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
		    cdb[2]);
		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
		spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
		trans_send_complete(cmd, STATUS_CHECK);
		return;
		break;
	}

	if (trans_send_datain(cmd, io->da_data, cdb[4], 0, sbc_io_free,
	    True, io) == False) {
		trans_send_complete(cmd, STATUS_BUSY);
	}
}
Example #20
0
/*ARGSUSED*/
static void
sbc_write(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	union scsi_cdb	*u;
	diskaddr_t	addr;
	uint64_t	err_blkno;
	uint32_t	cnt;
	uchar_t		addl_sense_len;
	disk_params_t	*d;
	disk_io_t	*io;
	size_t		max_out;
	void		*mmap_area;

	if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL)
		return;

	/*LINTED*/
	u = (union scsi_cdb *)cdb;

	switch (u->scc_cmd) {
	case SCMD_WRITE:
		/*
		 * SBC-2 revision 16, section 5.24
		 * Reserve bit checks.
		 */
		if ((cdb[1] & 0xe0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}
		addr = (diskaddr_t)(uint32_t)GETG0ADDR(u);
		cnt = GETG0COUNT(u);
		/*
		 * SBC-2 Revision 16/Section 5.24 WRITE(6)
		 * A TRANSFER LENGHT of 0 indicates that 256 logical blocks
		 * shall be written.
		 */
		if (cnt == 0)
			cnt = 256;
		break;

	case SCMD_WRITE_G1:
		/*
		 * SBC-2 revision 16, section 5.25
		 * Reserve bit checks.
		 */
		if ((cdb[1] & 0x6) || cdb[6] ||
		    SAM_CONTROL_BYTE_RESERVED(cdb[9])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}
		addr = (diskaddr_t)(uint32_t)GETG1ADDR(u);
		cnt = GETG1COUNT(u);
		break;

	case SCMD_WRITE_G4:
		/*
		 * SBC-2 revision 16, section 5.27
		 * Reserve bit checks.
		 */
		if ((cdb[1] & 0x6) || cdb[14] ||
		    SAM_CONTROL_BYTE_RESERVED(cdb[15])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}
		addr = (diskaddr_t)GETG4LONGADDR(u);
		cnt = GETG4COUNT(u);
		break;

	default:
		queue_prt(mgmtq, Q_STE_ERRS, "Unprocessed WRITE type");
		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
		spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
		trans_send_complete(cmd, STATUS_CHECK);
		return;

	}

	if ((addr + cnt) > d->d_size) {

		if (addr > d->d_size)
			err_blkno = addr;
		else
			err_blkno = d->d_size;

		/*
		 * XXX: What's SBC-2 say about ASC/ASCQ here. Solaris
		 * doesn't care about these values when key is set
		 * to KEY_ILLEGAL_REQUEST.
		 */
		if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN)
			addl_sense_len = INFORMATION_SENSE_DESCR;
		else
			addl_sense_len = 0;

		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len);
		spc_sense_info(cmd, err_blkno);
		spc_sense_ascq(cmd, 0x21, 0x00);
		trans_send_complete(cmd, STATUS_CHECK);

		queue_prt(mgmtq, Q_STE_ERRS,
		    "SBC%x  LUN%d WRITE Illegal sector "
		    "(0x%llx + 0x%x) > 0x%ullx", cmd->c_lu->l_targ->s_targ_num,
		    cmd->c_lu->l_common->l_num, addr, cnt, d->d_size);
		return;
	}

	if (cnt == 0) {
		queue_prt(mgmtq, Q_STE_NONIO,
		    "SBC%x  LUN%d WRITE zero block count for addr 0x%x",
		    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
		    addr);
		trans_send_complete(cmd, STATUS_GOOD);
		return;
	}

	io = (disk_io_t *)cmd->c_emul_id;
	if (io == NULL) {
		io = sbc_io_alloc(cmd);
		io->da_lba		= addr;
		io->da_lba_cnt		= cnt;
		io->da_clear_overlap	= False;
		io->da_aio.a_aio_cmplt	= sbc_write_cmplt;
		io->da_aio.a_id		= io;

		/*
		 * Only update the statistics the first time through
		 * for this particular command. If the requested transfer
		 * is larger than the transport can handle this routine
		 * will be called many times.
		 */
		cmd->c_lu->l_cmds_write++;
		cmd->c_lu->l_sects_write += cnt;
	}

#ifdef FULL_DEBUG
	queue_prt(mgmtq, Q_STE_IO,
	    "SBC%x  LUN%d blk 0x%llx, cnt %d, offset 0x%llx, size %d",
	    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, addr,
	    cnt, io->da_offset, io->da_data_len);
#endif

	/*
	 * If a transport sets the maximum output value to zero we'll
	 * just request the entire amount. Otherwise, transfer no more
	 * than the maximum output or the reminder, whichever is less.
	 */
	max_out = cmd->c_lu->l_targ->s_maxout;
	io->da_data_len = max_out ? MIN(max_out,
	    (cnt * 512) - io->da_offset) : (cnt * 512);

	mmap_area = T10_MMAP_AREA(cmd);
	if (mmap_area != MAP_FAILED) {

		io->da_data_alloc	= False;
		io->da_data		= (char *)mmap_area + (addr * 512LL) +
		    io->da_offset;
		sbc_overlap_check(io);

	} else if ((io->da_data = (char *)malloc(io->da_data_len)) == NULL) {

		trans_send_complete(cmd, STATUS_BUSY);
		return;

	} else {

		io->da_data_alloc	= True;
	}
	if (trans_rqst_dataout(cmd, io->da_data, io->da_data_len,
	    io->da_offset, io) == False) {
		trans_send_complete(cmd, STATUS_BUSY);
	}
}
Example #21
0
/*ARGSUSED*/
static void
sbc_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len)
{
	/*LINTED*/
	union scsi_cdb	*u		= (union scsi_cdb *)cdb;
	diskaddr_t	addr;
	off_t		offset		= 0;
	uint32_t	cnt,
			min;
	disk_io_t	*io;
	void		*mmap_data	= T10_MMAP_AREA(cmd);
	uint64_t	err_blkno;
	disk_params_t	*d;
	uchar_t		addl_sense_len;

	if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL)
		return;

	switch (u->scc_cmd) {
	case SCMD_READ:
		/*
		 * SBC-2 Revision 16, section 5.5
		 * Reserve bit checks
		 */
		if ((cdb[1] & 0xe0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}

		addr = (diskaddr_t)(uint32_t)GETG0ADDR(u);
		cnt = GETG0COUNT(u);

		/*
		 * SBC-2 Revision 16
		 * Section: 5.5 READ(6) command
		 *	A TRANSFER LENGTH field set to zero specifies
		 *	that 256 logical blocks shall be read.
		 */
		if (cnt == 0)
			cnt = 256;
		break;

	case SCMD_READ_G1:
		/*
		 * SBC-2 Revision 16, section 5.6
		 * Reserve bit checks.
		 */
		if ((cdb[1] & 6) || cdb[6] ||
		    SAM_CONTROL_BYTE_RESERVED(cdb[9])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}

		addr = (diskaddr_t)(uint32_t)GETG1ADDR(u);
		cnt = GETG1COUNT(u);
		break;

	case SCMD_READ_G4:
		/*
		 * SBC-2 Revision 16, section 5.8
		 * Reserve bit checks
		 */
		if ((cdb[1] & 0x6) || cdb[14] ||
		    SAM_CONTROL_BYTE_RESERVED(cdb[15])) {
			spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
			spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00);
			trans_send_complete(cmd, STATUS_CHECK);
			return;
		}

		addr = GETG4LONGADDR(u);
		cnt = GETG4COUNT(u);
		break;

	default:
		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
		trans_send_complete(cmd, STATUS_CHECK);
		return;
	}

	if ((addr + cnt) > d->d_size) {

		if (addr > d->d_size)
			err_blkno = addr;
		else
			err_blkno = d->d_size;

		/*
		 * XXX: What's SBC-2 say about ASC/ASCQ here. Solaris
		 * doesn't care about these values when key is set
		 * to KEY_ILLEGAL_REQUEST.
		 */
		if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN)
			addl_sense_len = INFORMATION_SENSE_DESCR;
		else
			addl_sense_len = 0;

		spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len);
		spc_sense_info(cmd, err_blkno);
		spc_sense_ascq(cmd, 0x21, 0x00);
		trans_send_complete(cmd, STATUS_CHECK);

		queue_prt(mgmtq, Q_STE_ERRS,
		    "SBC%x  LUN%d READ Illegal sector "
		    "(0x%llx + 0x%x) > 0x%ullx", cmd->c_lu->l_targ->s_targ_num,
		    cmd->c_lu->l_common->l_num, addr, cnt, d->d_size);
		return;
	}

	cmd->c_lu->l_cmds_read++;
	cmd->c_lu->l_sects_read += cnt;

	if (cnt == 0) {
		trans_send_complete(cmd, STATUS_GOOD);
		return;
	}

	do {
		io = sbc_io_alloc(cmd);
		min = MIN((cnt * 512) - offset, T10_MAX_OUT(cmd));

		io->da_lba	= addr;
		io->da_lba_cnt	= cnt;
		io->da_offset	= offset;
		io->da_data_len	= min;

#ifdef FULL_DEBUG
		queue_prt(mgmtq, Q_STE_IO,
		    "SBC%x  LUN%d blk 0x%llx, cnt %d, offset 0x%llx, size %d",
		    cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num,
		    addr, cnt, io->da_offset, min);
#endif
		if (mmap_data != MAP_FAILED) {

			io->da_clear_overlap		= True;
			io->da_data_alloc		= False;
			io->da_aio.a_aio.aio_return	= min;
			io->da_data = (char *)mmap_data + (addr * 512LL) +
			    io->da_offset;
			sbc_overlap_store(io);
			sbc_read_cmplt((emul_handle_t)io);

		} else {
			if ((io->da_data = (char *)malloc(min)) == NULL) {
				trans_send_complete(cmd, STATUS_BUSY);
				return;
			}
			io->da_clear_overlap	= False;
			io->da_data_alloc	= True;
			io->da_aio.a_aio_cmplt	= sbc_read_cmplt;
			io->da_aio.a_id		= io;
			trans_aioread(cmd, io->da_data, min, (addr * 512LL) +
			    (off_t)io->da_offset, (aio_result_t *)io);
		}
		offset += min;
	} while (offset < (off_t)(cnt * 512));
}
Example #22
0
/*
 * DevAttrQry for iscsi initiator
 * See RFC 4171 Sect. 5.6.5.2 for query detail
 */
static int
isns_dev_attr_qry(int so, char *target, char *initiator)
{
	isns_pdu_t	*cmd;
	isns_rsp_t	*rsp;
	uint32_t	flags = 0;
	int		ret = -1;
	size_t		remain;
	isns_tlv_t	*tlv;
	uint8_t		*ptr;

	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_QRY");

	if (isns_create_pdu(ISNS_DEV_ATTR_QRY, flags, &cmd) != 0) {
		return (-1);
	}

	/* source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(target), target, 0) == -1) {
		goto error;
	}

	/* message key attribute */
	/* iscsi initiator node type */
	if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
	    ISNS_NODE_TYP_SZ, NULL, ISNS_INITIATOR_NODE_TYPE) == -1) {
		goto error;
	}

	/* delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
		goto error;
	}

	/*
	 * operating attributes
	 * Query Iscsi initiator with zero length TLV operating
	 * attribute
	 */

	/* iscsi name */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    0, NULL, 0) != 0) {
		goto error;
	}

	if (isns_send(so, cmd) == -1) {
		syslog(LOG_ERR, "isns_dev_attr_qry fails isns_send");
		goto error;
	}

	/* recv response */
	if (isns_recv(so, &rsp) == -1) {
		syslog(LOG_ERR, "isns_dev_attr_qry fails isns_recv ");
		goto error;
	}

	/* process response */
	if ((ret = process_rsp(cmd, rsp)) == 0) {
		/* compare initiator name to the response, success if found */
		/* subtract out status word */
		remain = rsp->pdu_len - ISNS_STATUS_SZ;
		ptr = rsp->data;

		while (remain > 0) {
			/* LINTED */
			tlv = (isns_tlv_t *)ptr;

			/* debug only */
			print_ntoh_tlv(tlv);

			/* process tag-len-value */
			ntoh_tlv(tlv);
			/*
			 * let's process the data, only interested
			 * in iscsi name, skip everything else for
			 * now.
			 */
			if (tlv->attr_id == ISNS_ISCSI_NAME_ATTR_ID) {
				if (strncmp((char *)tlv->attr_value, initiator,
				    tlv->attr_len) == 0) {
					break;
				}
			}
			/* next tlv */
			remain -= ISNS_ATTR_SZ(tlv->attr_len);
			ptr += ISNS_ATTR_SZ(tlv->attr_len);
		}
		ret = (remain > 0) ? 1 : 0;
	}

error:
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	return (ret);
}
Example #23
0
/*
 * process_scn()
 *	-Added/Updated object: nop, initiator is verified during connect
 *
 *	-Removed object: logout_targ if still connected
 *
 * RFC 4171 section 5.6.5.9
 * destination attribute is always the 1st attribute in the SCN message,
 * then follows by SCN_BITMAP(35) & Source_Attribute(32)
 */
static void
process_scn(int so, isns_pdu_t *scn)
{
	uint8_t		*ptr = scn->payload;
	isns_tlv_t	*tlv;
	uint16_t	cnt = 0;
	uint32_t	got_dest = 0;
	uint32_t	got_source = 0;
	uint32_t	bitmap = 0;
	uint32_t	got_bitmap = 0;
	char		dest[MAXNAMELEN];
	char		source[MAXNAMELEN];

	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u\n",
	    scn->payload_len);

	if (scn->payload_len < TAG_LEN_SZ) {
		syslog(LOG_ALERT, "ISNS SCN message error\n");
		return;
	}

	while (cnt < scn->payload_len) {
		/* LINTED */
		tlv = (isns_tlv_t *)ptr;
		tlv->attr_id = ntohl(tlv->attr_id);
		tlv->attr_len = ntohl(tlv->attr_len);
		queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u %u\n",
		    tlv->attr_id, tlv->attr_len);
		/*
		 * devAttrQry the source attribute, process if node_type
		 * is initiator
		 */
		switch (tlv->attr_id) {
			case ISNS_ISCSI_NAME_ATTR_ID:
				if (got_dest == 0) {
					bcopy(tlv->attr_value, dest,
					    tlv->attr_len);
					queue_prt(mgmtq, Q_ISNS_DBG,
					    "PROCESS_SCN dest %s\n", dest);
					got_dest = 1;
				} else {
					bcopy(tlv->attr_value, source,
					    tlv->attr_len);
					queue_prt(mgmtq, Q_ISNS_DBG,
					    "PROCESS_SCN source %s\n", source);
					got_source = 1;
				}
				break;
			case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
				bcopy(tlv->attr_value, &bitmap, tlv->attr_len);
				bitmap = ntohl(bitmap);
				queue_prt(mgmtq, Q_ISNS_DBG,
				    "PROCESS_SCN bitmap %u\n", bitmap);
				got_bitmap = 1;
				break;
			default:
				queue_prt(mgmtq, Q_ISNS_DBG,
				    "PROCESS_SCN DEFAULT\n");
				break;
		}

		if (got_source && !got_bitmap) {
			queue_prt(mgmtq, Q_ISNS_DBG,
			    "process_scn: message out-of-order\n");
			return;
		}

		if (got_source && got_bitmap) {
			switch (bitmap) {
				case ISNS_OBJ_ADDED:
				case ISNS_OBJ_UPDATED:
					queue_prt(mgmtq, Q_ISNS_DBG,
					    "PROCESS_SCN OBJ ADDED");
					(void) isns_update();
					break;
				case ISNS_OBJ_REMOVED:
					queue_prt(mgmtq, Q_ISNS_DBG,
					    "PROCESS_SCN OBJ REMOVED");
					/* logout target */
					if (got_dest == 0) {
						syslog(LOG_ALERT,
						    "ISNS protocol error\n");
						continue;
					}
					logout_targ(dest);
					break;
				default:
					break;
			}

			/* clear got_xxx */
			got_source = 0;
			got_bitmap = 1;
		}

		/* next attribute */
		cnt += ISNS_ATTR_SZ(tlv->attr_len);
		ptr += ISNS_ATTR_SZ(tlv->attr_len);
	}
	queue_prt(mgmtq, Q_ISNS_DBG, "DONE PROCESS_SCN\n");
}
Example #24
0
/*
 * DevAttrDereg
 */
static int
isns_dev_attr_dereg(int so, char *node)
{
	isns_pdu_t	*cmd = NULL;
	isns_rsp_t	*rsp = NULL;
	uint32_t	flags = 0;
	int		ret = -1;

	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_DEREG");

	if (isns_create_pdu(ISNS_DEV_DEREG, flags, &cmd) != 0) {
		return (-1);
	}

	/* add source attribute */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) != 0) {
		goto error;
	}

	/* add delimiter */
	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
		goto error;
	}

	/* add operation attributes */
	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
	    STRLEN(node), node, 0) != 0) {
		goto error;
	}

	/* send pdu */
	if (isns_send(so, cmd) == -1) {
		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_send");
		goto error;
	}

	/* get isns response */
	if (isns_recv(so, &rsp) == -1) {
		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_recv ");
		goto error;
	}

	/* process response */
	if (process_rsp(cmd, rsp) == 0) {
		/*
		 * Keep the num_reg to a non-negative number.
		 * num_reg is used to keep track of whether there was
		 * any registration occurred or not. Deregstration should
		 * be followed by registration but in case dereg occurs
		 * and somehow it is succeeded keeping num_reg to 0 prevent
		 * any negative effect on subsequent registration.
		 */
		if (num_reg > 0) num_reg--;
		ret = 0;
	}

error:
	/* Free all resouces here */
	if (cmd)
		isns_free_pdu(cmd);
	if (rsp)
		isns_free_pdu(rsp);
	return (ret);
}