/* * Function name: tw_cli_complete_io * Description: CL internal callback for SCSI/fw passthru requests. * * Input: req -- ptr to CL internal request context * Output: None * Return value: None */ TW_VOID tw_cli_complete_io(struct tw_cli_req_context *req) { struct tw_cli_ctlr_context *ctlr = req->ctlr; struct tw_cl_req_packet *req_pkt = (struct tw_cl_req_packet *)(req->orig_req); tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); req_pkt->status = TW_CL_ERR_REQ_SUCCESS; if (req->error_code) { req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND; goto out; } if (req->state != TW_CLI_REQ_STATE_COMPLETE) { tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING, "I/O completion on incomplete command!!", "request = %p, status = %d", req, req->state); #ifdef TW_OSL_DEBUG tw_cl_print_ctlr_stats(ctlr->ctlr_handle); #endif /* TW_OSL_DEBUG */ tw_cl_reset_ctlr(ctlr->ctlr_handle); req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; goto out; } if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { /* Copy the command packet back into OSL's space. */ tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt, sizeof(struct tw_cl_command_packet)); } else tw_cli_scsi_complete(req); out: req_pkt->tw_osl_callback(req->req_handle); tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); }
/* * 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; }
/* * Function name: tw_cl_start_io * Description: Interface to OS Layer for accepting SCSI requests. * * Input: ctlr_handle -- controller handle * req_pkt -- OSL built request packet * req_handle -- request handle * Output: None * Return value: 0 -- success * non-zero-- failure */ TW_INT32 tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) { struct tw_cli_ctlr_context *ctlr; struct tw_cli_req_context *req; struct tw_cl_command_9k *cmd; struct tw_cl_scsi_req_packet *scsi_req; TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); /* * If working with a firmware version that does not support multiple * luns, and this request is directed at a non-zero lun, error it * back right away. */ if ((req_pkt->gen_req_pkt.scsi_req.lun) && (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) { req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN | TW_CL_ERR_REQ_SCSI_ERROR); req_pkt->tw_osl_callback(req_handle); return(TW_CL_ERR_REQ_SUCCESS); } if ((req = tw_cli_get_request(ctlr )) == TW_CL_NULL) { tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "Out of request context packets: returning busy"); return(TW_OSL_EBUSY); } req_handle->cl_req_ctxt = req; req->req_handle = req_handle; req->orig_req = req_pkt; req->tw_cli_callback = tw_cli_complete_io; req->flags |= TW_CLI_REQ_FLAGS_EXTERNAL; req->flags |= TW_CLI_REQ_FLAGS_9K; scsi_req = &(req_pkt->gen_req_pkt.scsi_req); /* Build the cmd pkt. */ cmd = &(req->cmd_pkt->command.cmd_pkt_9k); req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; cmd->res__opcode = BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); cmd->unit = (TW_UINT8)(scsi_req->unit); cmd->lun_l4__req_id = TW_CL_SWAP16( BUILD_LUN_L4__REQ_ID(scsi_req->lun, req->request_id)); cmd->status = 0; cmd->sgl_offset = 16; /* offset from end of hdr = max cdb len */ tw_osl_memcpy(cmd->cdb, scsi_req->cdb, scsi_req->cdb_len); if (req_pkt->flags & TW_CL_REQ_CALLBACK_FOR_SGLIST) { TW_UINT32 num_sgl_entries; req_pkt->tw_osl_sgl_callback(req_handle, cmd->sg_list, &num_sgl_entries); cmd->lun_h4__sgl_entries = TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, num_sgl_entries)); } else { cmd->lun_h4__sgl_entries = TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, scsi_req->sgl_entries)); tw_cli_fill_sg_list(ctlr, scsi_req->sg_list, cmd->sg_list, scsi_req->sgl_entries); } if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || (ctlr->reset_in_progress)) { tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); } else if ((error = tw_cli_submit_cmd(req))) { tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "Could not start request. request = %p, error = %d", req, error); tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); } return(error); }