示例#1
0
/*
 * Function name:	tw_cli_aen_callback
 * Description:		Callback for requests to fetch AEN's.
 *
 * Input:		req	-- ptr to completed request pkt
 * Output:		None
 * Return value:	None
 */
TW_VOID
tw_cli_aen_callback(struct tw_cli_req_context *req)
{
	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
	struct tw_cl_command_header	*cmd_hdr;
	struct tw_cl_command_9k		*cmd =
		&(req->cmd_pkt->command.cmd_pkt_9k);
	TW_UINT16			aen_code = TWA_AEN_QUEUE_EMPTY;
	TW_INT32			error;

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
		"req_id = 0x%x, req error = %d, status = 0x%x",
		GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);

	/*
	 * If the request was never submitted to the controller, the function
	 * that sets error is responsible for calling tw_cl_create_event.
	 */
	if (!(error = req->error_code))
		if ((error = cmd->status)) {
			cmd_hdr = (struct tw_cl_command_header *)
				(&(req->cmd_pkt->cmd_hdr));
			tw_cli_create_ctlr_event(ctlr,
				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
				cmd_hdr);
			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
				0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
				"Request Sense failed",
				"opcode = 0x%x, status = %d",
				GET_OPCODE(cmd->res__opcode), cmd->status);
		}

	if (error) {
		ctlr->internal_req_busy = TW_CL_FALSE;
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
		return;
	}

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
		"Request Sense command succeeded");

	aen_code = tw_cli_manage_aen(ctlr, req);

	if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
		ctlr->internal_req_busy = TW_CL_FALSE;
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
		if (aen_code != TWA_AEN_QUEUE_EMPTY)
			if ((error = tw_cli_get_aen(ctlr)))
				tw_cl_create_event(ctlr->ctlr_handle,
					TW_CL_FALSE,
					TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
					0x1207, 0x1,
					TW_CL_SEVERITY_ERROR_STRING,
					"Failed to fetch all AEN's",
					"error = %d", error);
	}
}
示例#2
0
/*
 * Function name:	tw_cli_param_callback
 * Description:		Callback for get/set_param requests.
 *
 * Input:		req	-- ptr to completed request pkt
 * Output:		None
 * Return value:	None
 */
TW_VOID
tw_cli_param_callback(struct tw_cli_req_context *req)
{
	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
	union tw_cl_command_7k		*cmd =
		&(req->cmd_pkt->command.cmd_pkt_7k);
	TW_INT32			error;

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");

	/*
	 * If the request was never submitted to the controller, the function
	 * that sets req->error is responsible for calling tw_cl_create_event.
	 */
	if (! req->error_code)
		if (cmd->param.status) {
#if       0
			tw_cli_create_ctlr_event(ctlr,
				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
				&(req->cmd_pkt->cmd_hdr));
#endif // 0
			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
				0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
				"get/set_param failed",
				"status = %d", cmd->param.status);
		}

	ctlr->internal_req_busy = TW_CL_FALSE;
	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);

	if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) {
		ctlr->get_more_aens = TW_CL_FALSE;
		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
			"Fetching more AEN's");
		if ((error = tw_cli_get_aen(ctlr)))
			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
				0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
				"Failed to fetch all AEN's from param_callback",
				"error = %d", error);
	}
}
示例#3
0
/*
 * Function name:	tw_cli_manage_aen
 * Description:		Handles AEN's.
 *
 * Input:		ctlr	-- ptr to CL internal ctlr context
 *			req	-- ptr to CL internal request context
 * Output:		None
 * Return value:	None
 */
TW_UINT16
tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
	struct tw_cli_req_context *req)
{
	struct tw_cl_command_header	*cmd_hdr;
	TW_UINT16			aen_code;
	TW_TIME				local_time;
	TW_TIME				sync_time;
	TW_UINT32			error;

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");

	cmd_hdr = (struct tw_cl_command_header *)(req->data);
	aen_code = cmd_hdr->status_block.error;

	switch (aen_code) {
	case TWA_AEN_SYNC_TIME_WITH_HOST:
		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
			"Received AEN_SYNC_TIME");
		/*
		 * Free the internal req pkt right here, since
		 * tw_cli_set_param will need it.
		 */
		ctlr->internal_req_busy = TW_CL_FALSE;
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);

		/*
		 * We will use a callback in tw_cli_set_param only when
		 * interrupts are enabled and we can expect our callback
		 * to get called.  Setting the get_more_aens
		 * flag will make the callback continue to try to retrieve
		 * more AEN's.
		 */
		if (ctlr->interrupts_enabled)
			ctlr->get_more_aens = TW_CL_TRUE;
		/* Calculate time (in seconds) since last Sunday 12.00 AM. */
		local_time = tw_osl_get_local_time();
		sync_time = (local_time - (3 * 86400)) % 604800;
		if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
				TWA_PARAM_TIME_SCHED_TIME, 4,
				&sync_time,
				(ctlr->interrupts_enabled)
				? tw_cli_param_callback : TW_CL_NULL)))
			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
				0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
				"Unable to sync time with ctlr",
				"error = %d", error);

		break;


	case TWA_AEN_QUEUE_EMPTY:
		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
			"AEN queue empty");
		break;


	default:
		/* Queue the event. */

		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
			"Queueing AEN");
		tw_cli_create_ctlr_event(ctlr,
			TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
			cmd_hdr);
		break;
	} /* switch */
	return(aen_code);
}
示例#4
0
/*
 * Function name:	tw_cli_scsi_complete
 * Description:		Completion routine for SCSI requests.
 *
 * Input:		req	-- ptr to CL internal request context
 * Output:		None
 * Return value:	None
 */
TW_VOID
tw_cli_scsi_complete(struct tw_cli_req_context *req)
{
	struct tw_cl_req_packet		*req_pkt =
		(struct tw_cl_req_packet *)(req->orig_req);
	struct tw_cl_scsi_req_packet	*scsi_req =
		&(req_pkt->gen_req_pkt.scsi_req);
	struct tw_cl_command_9k		*cmd =
		&(req->cmd_pkt->command.cmd_pkt_9k);
	struct tw_cl_command_header	*cmd_hdr;
	TW_UINT16			error;
	TW_UINT8			*cdb;

	tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
		"entered");

	scsi_req->scsi_status = cmd->status;
	if (! cmd->status)
		return;

	tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
		"req_id = 0x%x, status = 0x%x",
		GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);

	cmd_hdr = &(req->cmd_pkt->cmd_hdr);
	error = cmd_hdr->status_block.error;
	if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
			(error == TWA_ERROR_UNIT_OFFLINE)) {
		if (GET_LUN_L4(cmd->lun_l4__req_id))
			req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
		else
			req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
	} else {
		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
			tw_osl_cur_func(),
			"cmd = %x %x %x %x %x %x %x",
			GET_OPCODE(cmd->res__opcode),
			GET_SGL_OFF(cmd->res__opcode),
			cmd->unit,
			cmd->lun_l4__req_id,
			cmd->status,
			cmd->sgl_offset,
			cmd->lun_h4__sgl_entries);

		cdb = (TW_UINT8 *)(cmd->cdb);
		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
			tw_osl_cur_func(),
			"cdb = %x %x %x %x %x %x %x %x "
			"%x %x %x %x %x %x %x %x",
			cdb[0], cdb[1], cdb[2], cdb[3],
			cdb[4], cdb[5], cdb[6], cdb[7],
			cdb[8], cdb[9], cdb[10], cdb[11],
			cdb[12], cdb[13], cdb[14], cdb[15]);

#if       0
		/* 
		 * Print the error. Firmware doesn't yet support
		 * the 'Mode Sense' cmd.  Don't print if the cmd
		 * is 'Mode Sense', and the error is 'Invalid field
		 * in CDB'.
		 */
		if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
			tw_cli_create_ctlr_event(req->ctlr,
				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
				cmd_hdr);
#endif // 0
	}

	if (scsi_req->sense_data) {
		tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
			TWA_SENSE_DATA_LENGTH);
		scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
		req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
	}
	req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
}
示例#5
0
/*
 * Function name:	tw_cli_init_connection
 * Description:		Sends init_connection cmd to firmware
 *
 * Input:		ctlr		-- ptr to per ctlr structure
 *			message_credits	-- max # of requests that we might send
 *					 down simultaneously.  This will be
 *					 typically set to 256 at init-time or
 *					after a reset, and to 1 at shutdown-time
 *			set_features	-- indicates if we intend to use 64-bit
 *					sg, also indicates if we want to do a
 *					basic or an extended init_connection;
 *
 * Note: The following input/output parameters are valid, only in case of an
 *		extended init_connection:
 *
 *			current_fw_srl		-- srl of fw we are bundled
 *						with, if any; 0 otherwise
 *			current_fw_arch_id	-- arch_id of fw we are bundled
 *						with, if any; 0 otherwise
 *			current_fw_branch	-- branch # of fw we are bundled
 *						with, if any; 0 otherwise
 *			current_fw_build	-- build # of fw we are bundled
 *						with, if any; 0 otherwise
 * Output:		fw_on_ctlr_srl		-- srl of fw on ctlr
 *			fw_on_ctlr_arch_id	-- arch_id of fw on ctlr
 *			fw_on_ctlr_branch	-- branch # of fw on ctlr
 *			fw_on_ctlr_build	-- build # of fw on ctlr
 *			init_connect_result	-- result bitmap of fw response
 * Return value:	0	-- success
 *			non-zero-- failure
 */
TW_INT32
tw_cli_init_connection(struct tw_cli_ctlr_context *ctlr,
	TW_UINT16 message_credits, TW_UINT32 set_features,
	TW_UINT16 current_fw_srl, TW_UINT16 current_fw_arch_id,
	TW_UINT16 current_fw_branch, TW_UINT16 current_fw_build,
	TW_UINT16 *fw_on_ctlr_srl, TW_UINT16 *fw_on_ctlr_arch_id,
	TW_UINT16 *fw_on_ctlr_branch, TW_UINT16 *fw_on_ctlr_build,
	TW_UINT32 *init_connect_result)
{
	struct tw_cli_req_context		*req;
	struct tw_cl_command_init_connect	*init_connect;
	TW_INT32				error = TW_OSL_EBUSY;
    
	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");

	/* Get a request packet. */
	if ((req = tw_cli_get_request(ctlr
		)) == TW_CL_NULL)
		goto out;

	req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;

	/* Build the cmd pkt. */
	init_connect = &(req->cmd_pkt->command.cmd_pkt_7k.init_connect);

	req->cmd_pkt->cmd_hdr.header_desc.size_header = 128;

	init_connect->res1__opcode =
		BUILD_RES__OPCODE(0, TWA_FW_CMD_INIT_CONNECTION);
   	init_connect->request_id =
		(TW_UINT8)(TW_CL_SWAP16(req->request_id));
	init_connect->message_credits = TW_CL_SWAP16(message_credits);
	init_connect->features = TW_CL_SWAP32(set_features);
	if (ctlr->flags & TW_CL_64BIT_ADDRESSES)
		init_connect->features |= TW_CL_SWAP32(TWA_64BIT_SG_ADDRESSES);
	if (set_features & TWA_EXTENDED_INIT_CONNECT) {
		/*
		 * Fill in the extra fields needed for an extended
		 * init_connect.
		 */
		init_connect->size = 6;
		init_connect->fw_srl = TW_CL_SWAP16(current_fw_srl);
		init_connect->fw_arch_id = TW_CL_SWAP16(current_fw_arch_id);
		init_connect->fw_branch = TW_CL_SWAP16(current_fw_branch);
		init_connect->fw_build = TW_CL_SWAP16(current_fw_build);
	} else
		init_connect->size = 3;

	/* Submit the command, and wait for it to complete. */
	error = tw_cli_submit_and_poll_request(req,
		TW_CLI_REQUEST_TIMEOUT_PERIOD);
	if (error == TW_OSL_ETIMEDOUT)
		/* Clean-up done by tw_cli_submit_and_poll_request. */
		return(error);
	if (error)
		goto out;
	if ((error = init_connect->status)) {
		tw_cli_create_ctlr_event(ctlr,
			TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
			&(req->cmd_pkt->cmd_hdr));
		goto out;
	}
	if (set_features & TWA_EXTENDED_INIT_CONNECT) {
		*fw_on_ctlr_srl = TW_CL_SWAP16(init_connect->fw_srl);
		*fw_on_ctlr_arch_id = TW_CL_SWAP16(init_connect->fw_arch_id);
		*fw_on_ctlr_branch = TW_CL_SWAP16(init_connect->fw_branch);
		*fw_on_ctlr_build = TW_CL_SWAP16(init_connect->fw_build);
		*init_connect_result = TW_CL_SWAP32(init_connect->result);
	}
	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
	return(error);

out:
	tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
		TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
		0x1016, 0x1, TW_CL_SEVERITY_ERROR_STRING,
		"init_connection failed",
		"error = %d", error);
	if (req)
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
	return(error);
}
示例#6
0
/*
 * Function name:	tw_cli_drain_aen_queue
 * Description:		Fetches all un-retrieved AEN's posted by fw.
 *
 * Input:		ctlr	-- ptr to CL internal ctlr context
 * Output:		None
 * Return value:	0	-- success
 *			non-zero-- failure
 */
TW_INT32
tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr)
{
	struct tw_cli_req_context	*req;
	struct tw_cl_command_header	*cmd_hdr;
	TW_TIME				end_time;
	TW_UINT16			aen_code;
	TW_INT32			error;

	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");

	for (;;) {
		if ((req = tw_cli_get_request(ctlr
			)) == TW_CL_NULL) {
			error = TW_OSL_EBUSY;
			break;
		}

		req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
		req->tw_cli_callback = TW_CL_NULL;
		if ((error = tw_cli_send_scsi_cmd(req,
				0x03 /* REQUEST_SENSE */))) {
			tw_cli_dbg_printf(1, ctlr->ctlr_handle,
				tw_osl_cur_func(),
				"Cannot send command to fetch aen");
			break;
		}

		end_time = tw_osl_get_local_time() +
			TW_CLI_REQUEST_TIMEOUT_PERIOD;
		do {
			if ((error = req->error_code))
				/*
				 * This will take care of completion due to
				 * a reset, or a failure in
				 * tw_cli_submit_pending_queue.
				 */
				goto out;

			tw_cli_process_resp_intr(req->ctlr);

			if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
				(req->state != TW_CLI_REQ_STATE_PENDING))
				break;
		} while (tw_osl_get_local_time() <= end_time);

		if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
			error = TW_OSL_ETIMEDOUT;
			break;
		}

		if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
			cmd_hdr = &req->cmd_pkt->cmd_hdr;
#if       0
			tw_cli_create_ctlr_event(ctlr,
				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
				cmd_hdr);
#endif // 0
			break;
		}

		aen_code = tw_cli_manage_aen(ctlr, req);
		if (aen_code == TWA_AEN_QUEUE_EMPTY)
			break;
		if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST)
			continue;

		ctlr->internal_req_busy = TW_CL_FALSE;
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
	}

out:
	if (req) {
		if (req->data)
			ctlr->internal_req_busy = TW_CL_FALSE;
		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
	}
	return(error);
}