1/* 2 * Copyright (c) 2004-07 Applied Micro Circuits Corporation. 3 * Copyright (c) 2004-05 Vinod Kashyap 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 10 unchanged lines hidden (view full) --- 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * |
27 * $FreeBSD: head/sys/dev/twa/tw_cl_io.c 212008 2010-08-30 19:15:04Z delphij $ |
28 */ 29 30/* 31 * AMCC'S 3ware driver for 9000 series storage controllers. 32 * 33 * Author: Vinod Kashyap 34 * Modifications by: Adam Radford 35 * Modifications by: Manjunath Ranganathaiah --- 33 unchanged lines hidden (view full) --- 69TW_INT32 70tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, 71 struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) 72{ 73 struct tw_cli_ctlr_context *ctlr; 74 struct tw_cli_req_context *req; 75 struct tw_cl_command_9k *cmd; 76 struct tw_cl_scsi_req_packet *scsi_req; |
77 TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; |
78 79 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 80 81 ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 82 |
83 /* 84 * If working with a firmware version that does not support multiple 85 * luns, and this request is directed at a non-zero lun, error it 86 * back right away. 87 */ 88 if ((req_pkt->gen_req_pkt.scsi_req.lun) && 89 (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) { 90 req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN | --- 43 unchanged lines hidden (view full) --- 134 } else { 135 cmd->lun_h4__sgl_entries = 136 TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, 137 scsi_req->sgl_entries)); 138 tw_cli_fill_sg_list(ctlr, scsi_req->sg_list, 139 cmd->sg_list, scsi_req->sgl_entries); 140 } 141 |
142 if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || 143 (ctlr->reset_in_progress)) { 144 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 145 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 146 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 147 } else if ((error = tw_cli_submit_cmd(req))) { |
148 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 149 "Could not start request. request = %p, error = %d", 150 req, error); 151 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 152 } 153 return(error); 154} 155 --- 9 unchanged lines hidden (view full) --- 165 * non-zero-- failure 166 */ 167TW_INT32 168tw_cli_submit_cmd(struct tw_cli_req_context *req) 169{ 170 struct tw_cli_ctlr_context *ctlr = req->ctlr; 171 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 172 TW_UINT32 status_reg; |
173 TW_INT32 error = 0; |
174 175 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 176 177 /* Serialize access to the controller cmd queue. */ 178 tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 179 180 /* For 9650SE first write low 4 bytes */ 181 if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 182 (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) 183 tw_osl_write_reg(ctlr_handle, 184 TWA_COMMAND_QUEUE_OFFSET_LOW, 185 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 186 |
187 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); |
188 if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) { 189 struct tw_cl_req_packet *req_pkt = 190 (struct tw_cl_req_packet *)(req->orig_req); 191 192 tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), 193 "Cmd queue full"); 194 195 if ((req->flags & TW_CLI_REQ_FLAGS_INTERNAL) 196 || ((req_pkt) && 197 (req_pkt->flags & TW_CL_REQ_RETRY_ON_BUSY)) 198 ) { 199 if (req->state != TW_CLI_REQ_STATE_PENDING) { 200 tw_cli_dbg_printf(2, ctlr_handle, 201 tw_osl_cur_func(), 202 "pending internal/ioctl request"); 203 req->state = TW_CLI_REQ_STATE_PENDING; 204 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); |
205 /* Unmask command interrupt. */ 206 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 207 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 208 } else 209 error = TW_OSL_EBUSY; 210 } else { |
211 error = TW_OSL_EBUSY; 212 } 213 } else { 214 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), 215 "Submitting command"); 216 217 /* Insert command into busy queue */ 218 req->state = TW_CLI_REQ_STATE_BUSY; --- 15 unchanged lines hidden (view full) --- 234 TWA_COMMAND_QUEUE_OFFSET_HIGH, 235 (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); 236 } else 237 tw_osl_write_reg(ctlr_handle, 238 TWA_COMMAND_QUEUE_OFFSET, 239 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 240 } 241 } |
242 |
243 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 244 245 return(error); 246} 247 248 249 250/* --- 14 unchanged lines hidden (view full) --- 265 struct tw_cli_ctlr_context *ctlr; 266 struct tw_cli_req_context *req; 267 union tw_cl_command_7k *cmd_7k; 268 struct tw_cl_command_9k *cmd_9k; 269 struct tw_cl_passthru_req_packet *pt_req; 270 TW_UINT8 opcode; 271 TW_UINT8 sgl_offset; 272 TW_VOID *sgl = TW_CL_NULL; |
273 TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; |
274 275 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); 276 277 ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 278 |
279 if ((req = tw_cli_get_request(ctlr 280 )) == TW_CL_NULL) { 281 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 282 "Out of request context packets: returning busy"); 283 return(TW_OSL_EBUSY); 284 } 285 286 req_handle->cl_req_ctxt = req; 287 req->req_handle = req_handle; 288 req->orig_req = req_pkt; 289 req->tw_cli_callback = tw_cli_complete_io; 290 |
291 req->flags |= TW_CLI_REQ_FLAGS_PASSTHRU; |
292 293 pt_req = &(req_pkt->gen_req_pkt.pt_req); 294 295 tw_osl_memcpy(req->cmd_pkt, pt_req->cmd_pkt, 296 pt_req->cmd_pkt_length); 297 /* Build the cmd pkt. */ 298 if ((opcode = GET_OPCODE(((TW_UINT8 *) 299 (pt_req->cmd_pkt))[sizeof(struct tw_cl_command_header)])) --- 30 unchanged lines hidden (view full) --- 330 ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2); 331 } 332 } 333 334 if (sgl) 335 tw_cli_fill_sg_list(ctlr, pt_req->sg_list, 336 sgl, pt_req->sgl_entries); 337 |
338 if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || 339 (ctlr->reset_in_progress)) { 340 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 341 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 342 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 343 } else if ((error = tw_cli_submit_cmd(req))) { |
344 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 345 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 346 0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING, 347 "Failed to start passthru command", 348 "error = %d", error); 349 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 350 } 351 return(error); --- 395 unchanged lines hidden (view full) --- 747 748 /* Build the cmd pkt. */ 749 cmd = &(req->cmd_pkt->command.cmd_pkt_7k); 750 751 req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 752 753 cmd->param.sgl_off__opcode = 754 BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM); |
755 cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id)); |
756 cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); 757 cmd->param.param_count = TW_CL_SWAP16(1); 758 759 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 760 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = 761 TW_CL_SWAP64(req->data_phys); 762 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = 763 TW_CL_SWAP32(req->length); --- 11 unchanged lines hidden (view full) --- 775 param->parameter_id = (TW_UINT8)(param_id); 776 param->parameter_size_bytes = TW_CL_SWAP16(param_size); 777 778 /* Submit the command. */ 779 if (callback == TW_CL_NULL) { 780 /* There's no call back; wait till the command completes. */ 781 error = tw_cli_submit_and_poll_request(req, 782 TW_CLI_REQUEST_TIMEOUT_PERIOD); |
783 if (error) 784 goto out; 785 if ((error = cmd->param.status)) { |
786#if 0 |
787 tw_cli_create_ctlr_event(ctlr, 788 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 789 &(req->cmd_pkt->cmd_hdr)); |
790#endif // 0 |
791 goto out; 792 } 793 tw_osl_memcpy(param_data, param->data, param_size); 794 ctlr->internal_req_busy = TW_CL_FALSE; 795 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 796 } else { 797 /* There's a call back. Simply submit the command. */ 798 req->tw_cli_callback = callback; --- 91 unchanged lines hidden (view full) --- 890 /* Specify which parameter we want to set. */ 891 param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); 892 param->parameter_id = (TW_UINT8)(param_id); 893 param->parameter_size_bytes = TW_CL_SWAP16(param_size); 894 tw_osl_memcpy(param->data, data, param_size); 895 896 /* Submit the command. */ 897 if (callback == TW_CL_NULL) { |
898 /* There's no call back; wait till the command completes. */ |
899 error = tw_cli_submit_and_poll_request(req, |
900 TW_CLI_REQUEST_TIMEOUT_PERIOD); |
901 if (error) 902 goto out; 903 if ((error = cmd->param.status)) { |
904#if 0 |
905 tw_cli_create_ctlr_event(ctlr, 906 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 907 &(req->cmd_pkt->cmd_hdr)); |
908#endif // 0 |
909 goto out; 910 } 911 ctlr->internal_req_busy = TW_CL_FALSE; 912 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 913 } else { 914 /* There's a call back. Simply submit the command. */ 915 req->tw_cli_callback = callback; 916 if ((error = tw_cli_submit_cmd(req))) --- 89 unchanged lines hidden (view full) --- 1006 */ 1007 1008 /* 1009 * We have to make sure that this timed out request, if it were in the 1010 * pending queue, doesn't get submitted while we are here, from 1011 * tw_cli_submit_pending_queue. There could be a race in that case. 1012 * Need to revisit. 1013 */ |
1014 if (req->state == TW_CLI_REQ_STATE_PENDING) { |
1015 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), 1016 "Removing request from pending queue"); 1017 /* 1018 * Request was never submitted. Clean up. Note that we did 1019 * not do a reset. So, we have to remove the request ourselves 1020 * from the pending queue (as against tw_cli_drain_pendinq_queue 1021 * taking care of it). 1022 */ --- 12 unchanged lines hidden (view full) --- 1035 1036 1037/* 1038 * Function name: tw_cl_reset_ctlr 1039 * Description: Soft resets and then initializes the controller; 1040 * drains any incomplete requests. 1041 * 1042 * Input: ctlr -- ptr to per ctlr structure |
1043 * req_handle -- ptr to request handle |
1044 * Output: None 1045 * Return value: 0 -- success 1046 * non-zero-- failure 1047 */ 1048TW_INT32 1049tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) 1050{ 1051 struct tw_cli_ctlr_context *ctlr = 1052 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1053 struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt; |
1054 struct tw_cli_req_context *req; |
1055 TW_INT32 reset_attempt = 1; |
1056 TW_INT32 error = 0; |
1057 1058 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered"); 1059 1060 ctlr->reset_in_progress = TW_CL_TRUE; |
1061 twa_teardown_intr(sc); |
1062 |
1063 1064 /* 1065 * Error back all requests in the complete, busy, and pending queues. 1066 * If any request is already on its way to getting submitted, it's in 1067 * none of these queues and so, will not be completed. That request 1068 * will continue its course and get submitted to the controller after 1069 * the reset is done (and io_lock is released). 1070 */ |
1071 tw_cli_drain_complete_queue(ctlr); 1072 tw_cli_drain_busy_queue(ctlr); 1073 tw_cli_drain_pending_queue(ctlr); 1074 ctlr->internal_req_busy = TW_CL_FALSE; 1075 ctlr->get_more_aens = TW_CL_FALSE; 1076 1077 /* Soft reset the controller. */ |
1078 while (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) { 1079 if ((error = tw_cli_soft_reset(ctlr))) { 1080 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1081 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1082 0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1083 "Controller reset failed", 1084 "error = %d; attempt %d", error, reset_attempt++); 1085 reset_attempt++; 1086 continue; 1087 } |
1088 |
1089 /* Re-establish logical connection with the controller. */ 1090 if ((error = tw_cli_init_connection(ctlr, 1091 (TW_UINT16)(ctlr->max_simult_reqs), 1092 0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL, 1093 TW_CL_NULL, TW_CL_NULL))) { 1094 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1095 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1096 0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1097 "Can't initialize connection after reset", 1098 "error = %d", error); 1099 reset_attempt++; 1100 continue; 1101 } 1102 1103#ifdef TW_OSL_DEBUG 1104 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, |
1105 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, |
1106 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, 1107 "Controller reset done!", " "); 1108#endif /* TW_OSL_DEBUG */ 1109 break; 1110 } /* End of while */ 1111 1112 /* Move commands from the reset queue to the pending queue. */ 1113 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_RESET_Q)) != TW_CL_NULL) { 1114 tw_osl_timeout(req->req_handle); 1115 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); |
1116 } 1117 |
1118 twa_setup_intr(sc); 1119 tw_cli_enable_interrupts(ctlr); 1120 if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) 1121 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 1122 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); |
1123 ctlr->reset_in_progress = TW_CL_FALSE; |
1124 ctlr->reset_needed = TW_CL_FALSE; |
1125 |
1126 /* Request for a bus re-scan. */ |
1127 tw_osl_scan_bus(ctlr_handle); 1128 |
1129 return(error); 1130} 1131 |
1132TW_VOID 1133tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) 1134{ 1135 struct tw_cli_ctlr_context *ctlr = 1136 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); |
1137 |
1138 ctlr->reset_needed = TW_CL_TRUE; 1139} |
1140 |
1141TW_INT32 1142tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) 1143{ 1144 struct tw_cli_ctlr_context *ctlr = 1145 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1146 1147 return(ctlr->reset_needed); 1148} 1149 1150TW_INT32 1151tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle) 1152{ 1153 struct tw_cli_ctlr_context *ctlr = 1154 (struct tw_cli_ctlr_context *) 1155 (ctlr_handle->cl_ctlr_ctxt); 1156 1157 return(ctlr->active); 1158} 1159 1160 1161 |
1162/* 1163 * Function name: tw_cli_soft_reset 1164 * Description: Does the actual soft reset. 1165 * 1166 * Input: ctlr -- ptr to per ctlr structure 1167 * Output: None 1168 * Return value: 0 -- success 1169 * non-zero-- failure 1170 */ 1171TW_INT32 1172tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) 1173{ 1174 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; |
1175 int found; 1176 int loop_count; 1177 TW_UINT32 error; 1178 1179 tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered"); 1180 |
1181 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, |
1182 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1183 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING, 1184 "Resetting controller...", 1185 " "); 1186 1187 /* Don't let any new commands get submitted to the controller. */ 1188 tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 1189 --- 18 unchanged lines hidden (view full) --- 1208 do { 1209 found = (tw_cli_find_response(ctlr, TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) == TW_OSL_ESUCCESS); 1210 tw_osl_delay(10); 1211 loop_count++; 1212 error = 0x7888; 1213 } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */ 1214 1215 if (!found) { |
1216 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, |
1217 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1218 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1219 "Missed firmware handshake after soft-reset", 1220 "error = %d", error); 1221 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1222 return(error); 1223 } 1224 1225 tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000); 1226 ctlr->reset_phase1_in_progress = TW_CL_FALSE; 1227 } 1228 1229 if ((error = tw_cli_poll_status(ctlr, 1230 TWA_STATUS_MICROCONTROLLER_READY | 1231 TWA_STATUS_ATTENTION_INTERRUPT, 1232 TW_CLI_RESET_TIMEOUT_PERIOD))) { |
1233 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, |
1234 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1235 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1236 "Micro-ctlr not ready/No attn intr after reset", 1237 "error = %d", error); 1238 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1239 return(error); 1240 } 1241 --- 17 unchanged lines hidden (view full) --- 1259 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1260 0x110B, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1261 "Can't drain AEN queue after reset", 1262 "error = %d", error); 1263 return(error); 1264 } 1265 1266 if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) { |
1267 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, |
1268 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1269 0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1270 "Reset not reported by controller", 1271 "error = %d", error); 1272 return(error); 1273 } |
1274 |
1275 return(TW_OSL_ESUCCESS); 1276} 1277 1278 1279 1280/* 1281 * Function name: tw_cli_send_scsi_cmd 1282 * Description: Sends down a scsi cmd to fw. --- 157 unchanged lines hidden --- |