5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Copyright (c) 2000 to 2010, LSI Corporation.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms of all code within
32 * this file that is exclusively owned by LSI, with or without
33 * modification, is permitted provided that, in addition to the CDDL 1.0
34 * License requirements, the following conditions are met:
35 *
36 * Neither the name of the author nor the names of its contributors may be
37 * used to endorse or promote products derived from this software without
38 * specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * DAMAGE.
52 */
53
54 /*
55 * mptsas_impl - This file contains all the basic functions for communicating
56 * to MPT based hardware.
57 */
58
59 #if defined(lint) || defined(DEBUG)
60 #define MPTSAS_DEBUG
61 #endif
62
63 /*
64 * standard header files
65 */
66 #include <sys/note.h>
67 #include <sys/scsi/scsi.h>
68 #include <sys/pci.h>
69
70 #pragma pack(1)
71 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
72 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
78 #pragma pack()
79
80 /*
81 * private header files.
82 */
83 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
84 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
85
86 /*
87 * FMA header files.
88 */
89 #include <sys/fm/io/ddi.h>
90
91 #if defined(MPTSAS_DEBUG)
92 extern uint32_t mptsas_debug_flags;
93 #endif
94
95 /*
96 * prototypes
97 */
98 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
99 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
100 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
101 struct mptsas_cmd *cmd);
102
103 /*
104 * add ioc evnet cmd into the queue
105 */
106 static void
107 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
108 {
109 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
110 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
111 mpt->m_ioc_event_cmdq = cmd;
112 } else {
188 } else {
189 /*
190 * it's not ack cmd, so continue to check next one
191 */
192
193 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
194 ioc_cmd = ioc_cmd->m_event_linkp;
195 }
196
197 }
198 }
199
200 void
201 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
202 {
203 pMpi2ConfigRequest_t request;
204 pMpi2SGESimple64_t sge;
205 struct scsi_pkt *pkt = cmd->cmd_pkt;
206 mptsas_config_request_t *config = pkt->pkt_ha_private;
207 uint8_t direction;
208 uint32_t length, flagslength, request_desc_low;
209
210 ASSERT(mutex_owned(&mpt->m_mutex));
211
212 /*
213 * Point to the correct message and clear it as well as the global
214 * config page memory.
215 */
216 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
217 (mpt->m_req_frame_size * cmd->cmd_slot));
218 bzero(request, mpt->m_req_frame_size);
219
220 /*
221 * Form the request message.
222 */
223 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
224 MPI2_FUNCTION_CONFIG);
225 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
226 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
227 length = 0;
228 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
242 config->ext_page_type);
243 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
244 config->ext_page_length);
245 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
246 config->page_type);
247 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
248 config->page_length);
249 ddi_put8(mpt->m_acc_req_frame_hdl,
250 &request->Header.PageVersion, config->page_version);
251 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
252 MPI2_CONFIG_PAGETYPE_EXTENDED) {
253 length = config->ext_page_length * 4;
254 } else {
255 length = config->page_length * 4;
256 }
257
258 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
259 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
260 }
261 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
262 (uint32_t)cmd->cmd_dma_addr);
263 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
264 (uint32_t)(cmd->cmd_dma_addr >> 32));
265 }
266 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
267 config->page_number);
268 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
269 config->page_address);
270 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
271 MPI2_SGE_FLAGS_END_OF_BUFFER |
272 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
273 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
274 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
275 direction |
276 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
277 flagslength |= length;
278 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
279
280 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
281 DDI_DMA_SYNC_FORDEV);
282 request_desc_low = (cmd->cmd_slot << 16) +
283 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
284 cmd->cmd_rfm = NULL;
285 MPTSAS_START_CMD(mpt, request_desc_low, 0);
286 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
287 DDI_SUCCESS) ||
288 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
289 DDI_SUCCESS)) {
290 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
291 }
292 }
293
294 int
295 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
296 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
297 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
298 {
299 va_list ap;
300 ddi_dma_attr_t attrs;
301 ddi_dma_cookie_t cookie;
302 ddi_acc_handle_t accessp;
303 size_t len = 0;
304 mptsas_config_request_t config;
305 int rval = DDI_SUCCESS, config_flags = 0;
306 mptsas_cmd_t *cmd;
307 struct scsi_pkt *pkt;
308 pMpi2ConfigReply_t reply;
309 uint16_t iocstatus = 0;
310 uint32_t iocloginfo;
311 caddr_t page_memp;
312
313 va_start(ap, callback);
314 ASSERT(mutex_owned(&mpt->m_mutex));
315
316 /*
317 * Get a command from the pool.
318 */
319 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
320 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
321 "page request");
322 rval = DDI_FAILURE;
323 goto page_done;
324 }
325 config_flags |= MPTSAS_REQUEST_POOL_CMD;
326
327 bzero((caddr_t)cmd, sizeof (*cmd));
328 bzero((caddr_t)pkt, scsi_pkt_size());
329 bzero((caddr_t)&config, sizeof (config));
330
331 /*
374 }
375
376 /*
377 * Check if the header request completed without timing out
378 */
379 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
380 mptsas_log(mpt, CE_WARN, "config header request timeout");
381 rval = DDI_FAILURE;
382 goto page_done;
383 }
384
385 /*
386 * cmd_rfm points to the reply message if a reply was given. Check the
387 * IOCStatus to make sure everything went OK with the header request.
388 */
389 if (cmd->cmd_rfm) {
390 config_flags |= MPTSAS_ADDRESS_REPLY;
391 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
392 DDI_DMA_SYNC_FORCPU);
393 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
394 - mpt->m_reply_frame_dma_addr));
395 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
396 &reply->Header.PageType);
397 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
398 &reply->Header.PageNumber);
399 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
400 &reply->Header.PageLength);
401 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
402 &reply->Header.PageVersion);
403 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
404 &reply->ExtPageType);
405 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
406 &reply->ExtPageLength);
407
408 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
409 &reply->IOCStatus);
410 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
411 &reply->IOCLogInfo);
412
413 if (iocstatus) {
414 NDBG13(("mptsas_access_config_page header: "
448 mpt->m_free_index = 0;
449 }
450 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
451 mpt->m_free_index);
452 config_flags &= (~MPTSAS_ADDRESS_REPLY);
453 }
454
455 /*
456 * Allocate DMA buffer here. Store the info regarding this buffer in
457 * the cmd struct so that it can be used for this specific command and
458 * de-allocated after the command completes. The size of the reply
459 * will not be larger than the reply frame size.
460 */
461 attrs = mpt->m_msg_dma_attr;
462 attrs.dma_attr_sgllen = 1;
463 attrs.dma_attr_granular = (uint32_t)len;
464
465 if (mptsas_dma_addr_create(mpt, attrs,
466 &cmd->cmd_dmahandle, &accessp, &page_memp,
467 len, &cookie) == FALSE) {
468 goto page_done;
469 }
470 cmd->cmd_dma_addr = cookie.dmac_laddress;
471 bzero(page_memp, len);
472
473 /*
474 * Save the data for this request to be used in the call to start the
475 * config page read
476 */
477 config.action = action;
478 config.page_address = page_address;
479
480 /*
481 * Re-use the cmd that was used to get the header. Reset some of the
482 * values.
483 */
484 bzero((caddr_t)pkt, scsi_pkt_size());
485 pkt->pkt_ha_private = (opaque_t)&config;
486 pkt->pkt_flags = FLAG_HEAD;
487 pkt->pkt_time = 60;
488 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
489
513 * Check if the request completed without timing out
514 */
515 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
516 mptsas_log(mpt, CE_WARN, "config page request timeout");
517 rval = DDI_FAILURE;
518 goto page_done;
519 }
520
521 /*
522 * cmd_rfm points to the reply message if a reply was given. The reply
523 * frame and the config page are returned from this function in the
524 * param list.
525 */
526 if (cmd->cmd_rfm) {
527 config_flags |= MPTSAS_ADDRESS_REPLY;
528 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
529 DDI_DMA_SYNC_FORCPU);
530 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
531 DDI_DMA_SYNC_FORCPU);
532 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
533 - mpt->m_reply_frame_dma_addr));
534 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
535 &reply->IOCStatus);
536 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
537 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
538 &reply->IOCLogInfo);
539 }
540
541 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
542 rval = DDI_FAILURE;
543 goto page_done;
544 }
545
546 mptsas_fma_check(mpt, cmd);
547 /*
548 * Check the DMA/ACC handles and then free the DMA buffer.
549 */
550 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
551 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
552 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
553 rval = DDI_FAILURE;
567 page_done:
568 va_end(ap);
569 /*
570 * Put the reply frame back on the free queue, increment the free
571 * index, and write the new index to the free index register. But only
572 * if this reply is an ADDRESS reply.
573 */
574 if (config_flags & MPTSAS_ADDRESS_REPLY) {
575 ddi_put32(mpt->m_acc_free_queue_hdl,
576 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
577 cmd->cmd_rfm);
578 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
579 DDI_DMA_SYNC_FORDEV);
580 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
581 mpt->m_free_index = 0;
582 }
583 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
584 mpt->m_free_index);
585 }
586
587 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
588
589 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
590 mptsas_remove_cmd(mpt, cmd);
591 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
592 }
593 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
594 mptsas_return_to_pool(mpt, cmd);
595
596 if (config_flags & MPTSAS_CMD_TIMEOUT) {
597 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
598 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
599 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
600 }
601 }
602
603 return (rval);
604 }
605
606 int
607 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
608 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
609 uint8_t pagelength, uint32_t SGEflagslength, uint32_t SGEaddress32)
610 {
611 pMpi2ConfigRequest_t config;
612 int send_numbytes;
613
614 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
615 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
616 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
617 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
618 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
619 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
620 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
621 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
622 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
623 ddi_put32(mpt->m_hshk_acc_hdl,
624 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
625 ddi_put32(mpt->m_hshk_acc_hdl,
626 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
627 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
628
629 /*
630 * Post message via handshake
631 */
632 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
633 mpt->m_hshk_acc_hdl)) {
634 return (-1);
635 }
636 return (0);
637 }
638
639 int
640 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
641 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
642 uint8_t pageversion, uint16_t extpagelength,
643 uint32_t SGEflagslength, uint32_t SGEaddress32)
644 {
645 pMpi2ConfigRequest_t config;
646 int send_numbytes;
647
648 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
649 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
650 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
651 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
652 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
653 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
654 MPI2_CONFIG_PAGETYPE_EXTENDED);
655 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
656 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
657 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
658 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
659 ddi_put32(mpt->m_hshk_acc_hdl,
660 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
661 ddi_put32(mpt->m_hshk_acc_hdl,
662 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
663 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
664
665 /*
666 * Post message via handshake
667 */
668 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
669 mpt->m_hshk_acc_hdl)) {
670 return (-1);
671 }
672 return (0);
673 }
674
675 int
676 mptsas_ioc_wait_for_response(mptsas_t *mpt)
677 {
678 int polls = 0;
679
680 while ((ddi_get32(mpt->m_datap,
681 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
682 drv_usecwait(1000);
1070 * priority queue with its limit and the controller will reply as they are
1071 * completed. This way, we don't have to poll for one reply at a time.
1072 * Think about enhancing this later.
1073 */
1074 int
1075 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1076 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1077 {
1078 /*
1079 * In order to avoid allocating variables on the stack,
1080 * we make use of the pre-existing mptsas_cmd_t and
1081 * scsi_pkt which are included in the mptsas_t which
1082 * is passed to this routine.
1083 */
1084
1085 pMpi2SCSITaskManagementRequest_t task;
1086 int rval = FALSE;
1087 mptsas_cmd_t *cmd;
1088 struct scsi_pkt *pkt;
1089 mptsas_slots_t *slots = mpt->m_active;
1090 uint32_t request_desc_low, i;
1091 pMPI2DefaultReply_t reply_msg;
1092
1093 /*
1094 * Can't start another task management routine.
1095 */
1096 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1097 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1098 " command at a time\n");
1099 return (FALSE);
1100 }
1101
1102 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1103 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1104
1105 bzero((caddr_t)cmd, sizeof (*cmd));
1106 bzero((caddr_t)pkt, scsi_pkt_size());
1107
1108 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1109 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1110 pkt->pkt_ha_private = (opaque_t)cmd;
1126 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1127 (mpt->m_req_frame_size * cmd->cmd_slot));
1128 bzero(task, mpt->m_req_frame_size);
1129
1130 /*
1131 * form message for requested task
1132 */
1133 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1134 MPI2_FUNCTION_SCSI_TASK_MGMT);
1135
1136 /*
1137 * Set the task type
1138 */
1139 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1140
1141 /*
1142 * Send TM request using High Priority Queue.
1143 */
1144 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1145 DDI_DMA_SYNC_FORDEV);
1146 request_desc_low = (cmd->cmd_slot << 16) +
1147 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1148 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1149 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1150
1151 if (pkt->pkt_reason == CMD_INCOMPLETE)
1152 rval = FALSE;
1153
1154 /*
1155 * If a reply frame was used and there is a reply buffer to copy the
1156 * reply data into, copy it. If this fails, log a message, but don't
1157 * fail the TM request.
1158 */
1159 if (cmd->cmd_rfm && reply) {
1160 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1161 DDI_DMA_SYNC_FORCPU);
1162 reply_msg = (pMPI2DefaultReply_t)
1163 (mpt->m_reply_frame + (cmd->cmd_rfm -
1164 mpt->m_reply_frame_dma_addr));
1165 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1166 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1167 }
1168 mutex_exit(&mpt->m_mutex);
1169 for (i = 0; i < reply_size; i++) {
1170 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1171 mode)) {
1172 mptsas_log(mpt, CE_WARN, "failed to copy out "
1173 "reply data for TM request");
1174 break;
1175 }
1176 }
1177 mutex_enter(&mpt->m_mutex);
1178 }
1179
1180 /*
1181 * clear the TM slot before returning
1182 */
1183 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1184
1185 /*
1186 * If we lost our task management command
1187 * we need to reset the ioc
1188 */
1189 if (rval == FALSE) {
1190 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1191 "try to reset ioc to recovery!");
1192 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1193 if (mptsas_restart_ioc(mpt)) {
1194 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1195 rval = FAILED;
1196 }
1197 }
1198
1199 return (rval);
1200 }
1201
1202 int
1203 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1204 uint8_t type, int mode)
1205 {
1206
1207 /*
1208 * In order to avoid allocating variables on the stack,
1209 * we make use of the pre-existing mptsas_cmd_t and
1210 * scsi_pkt which are included in the mptsas_t which
1211 * is passed to this routine.
1212 */
1213
1214 ddi_dma_attr_t flsh_dma_attrs;
1215 ddi_dma_cookie_t flsh_cookie;
1216 ddi_dma_handle_t flsh_dma_handle;
1217 ddi_acc_handle_t flsh_accessp;
1218 caddr_t memp, flsh_memp;
1219 uint32_t flagslength;
1220 pMpi2FWDownloadRequest fwdownload;
1221 pMpi2FWDownloadTCSGE_t tcsge;
1222 pMpi2SGESimple64_t sge;
1223 mptsas_cmd_t *cmd;
1224 struct scsi_pkt *pkt;
1225 int i;
1226 int rvalue = 0;
1227 uint32_t request_desc_low;
1228
1229 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1230 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1231 "failed. event ack command pool is full\n");
1232 return (rvalue);
1233 }
1234
1235 bzero((caddr_t)cmd, sizeof (*cmd));
1236 bzero((caddr_t)pkt, scsi_pkt_size());
1237 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1238
1239 /*
1240 * dynamically create a customized dma attribute structure
1241 * that describes the flash file.
1242 */
1243 flsh_dma_attrs = mpt->m_msg_dma_attr;
1244 flsh_dma_attrs.dma_attr_sgllen = 1;
1245
1246 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1247 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1268 pkt->pkt_time = 60;
1269 cmd->cmd_pkt = pkt;
1270 cmd->cmd_scblen = 1;
1271 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1272
1273 /*
1274 * Save the command in a slot
1275 */
1276 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1277 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1278 mptsas_return_to_pool(mpt, cmd);
1279 return (-1);
1280 }
1281
1282 /*
1283 * Fill in fw download message
1284 */
1285 ASSERT(cmd->cmd_slot != 0);
1286 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1287 bzero(memp, mpt->m_req_frame_size);
1288 fwdownload = (void *)memp;
1289 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->Function,
1290 MPI2_FUNCTION_FW_DOWNLOAD);
1291 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->ImageType, type);
1292 ddi_put8(mpt->m_acc_req_frame_hdl, &fwdownload->MsgFlags,
1293 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1294 ddi_put32(mpt->m_acc_req_frame_hdl, &fwdownload->TotalImageSize, size);
1295
1296 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1297 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->ContextSize, 0);
1298 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->DetailsLength, 12);
1299 ddi_put8(mpt->m_acc_req_frame_hdl, &tcsge->Flags, 0);
1300 ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageOffset, 0);
1301 ddi_put32(mpt->m_acc_req_frame_hdl, &tcsge->ImageSize, size);
1302
1303 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1304 flagslength = size;
1305 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1306 MPI2_SGE_FLAGS_END_OF_BUFFER |
1307 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1308 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1309 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1310 MPI2_SGE_FLAGS_HOST_TO_IOC |
1311 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1312 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
1313 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
1314 flsh_cookie.dmac_address);
1315 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
1316 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1317
1318 /*
1319 * Start command
1320 */
1321 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1322 DDI_DMA_SYNC_FORDEV);
1323 request_desc_low = (cmd->cmd_slot << 16) +
1324 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1325 cmd->cmd_rfm = NULL;
1326 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1327
1328 rvalue = 0;
1329 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1330 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1331 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1332 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1333 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1334 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1335 }
1336 rvalue = -1;
1337 }
1338 mptsas_remove_cmd(mpt, cmd);
1339 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1340
1341 return (rvalue);
1342 }
1343
1344 static int
1345 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1346 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1347 va_list ap)
1348 {
1349 #ifndef __lock_lint
1350 _NOTE(ARGUNUSED(ap))
1351 #endif
1352 pMpi2SasDevicePage0_t sasdevpage;
1353 int rval = DDI_SUCCESS, i;
1354 uint8_t *sas_addr = NULL;
1355 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1356 uint16_t *devhdl, *bay_num, *enclosure;
1357 uint64_t *sas_wwn;
1358 uint32_t *dev_info;
1359 uint8_t *physport, *phynum;
1360 uint16_t *pdevhdl;
1361 uint32_t page_address;
1362
1363 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1364 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1365 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1366 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1367 iocstatus, iocloginfo);
1368 rval = DDI_FAILURE;
1369 return (rval);
1370 }
1371 page_address = va_arg(ap, uint32_t);
1372 /*
1373 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1374 * are no more pages. If everything is OK up to this point but the
1375 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1376 * signal that device traversal is complete.
1377 */
1378 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1379 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1380 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1381 mpt->m_done_traverse_dev = 1;
1382 }
1383 rval = DDI_FAILURE;
1384 return (rval);
1385 }
1386 devhdl = va_arg(ap, uint16_t *);
1387 sas_wwn = va_arg(ap, uint64_t *);
1388 dev_info = va_arg(ap, uint32_t *);
1389 physport = va_arg(ap, uint8_t *);
1390 phynum = va_arg(ap, uint8_t *);
1391 pdevhdl = va_arg(ap, uint16_t *);
1392 bay_num = va_arg(ap, uint16_t *);
1393 enclosure = va_arg(ap, uint16_t *);
1394
1395
1396 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1397
1398 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1399 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1400 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1401 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1402 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1403 }
1404 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1405 *sas_wwn = LE_64(*sas_wwn);
1406 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1407 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1408 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1409 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1410 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1411 return (rval);
1412 }
1413
1414 /*
1415 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1416 * info and SAS address.
1417 */
1418 int
1419 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1420 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1421 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1422 uint16_t *bay_num, uint16_t *enclosure)
1423 {
1424 int rval = DDI_SUCCESS;
1425
1426 ASSERT(mutex_owned(&mpt->m_mutex));
1427
1428 /*
1429 * Get the header and config page. reply contains the reply frame,
1430 * which holds status info for the request.
1431 */
1432 rval = mptsas_access_config_page(mpt,
1433 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1434 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1435 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1436 dev_info, physport, phynum, pdev_handle,
1437 bay_num, enclosure);
1438
1439 return (rval);
1440 }
1441
1442 static int
1443 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1444 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1445 va_list ap)
1446 {
1447 #ifndef __lock_lint
1448 _NOTE(ARGUNUSED(ap))
1449 #endif
1450 pMpi2ExpanderPage0_t expddevpage;
1451 int rval = DDI_SUCCESS, i;
1452 uint8_t *sas_addr = NULL;
1453 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1454 uint16_t *devhdl;
1455 uint64_t *sas_wwn;
1456 uint8_t physport;
1457 mptsas_phymask_t *phymask;
1840 pMpi2ConfigReply_t configreply;
1841 pMpi2SasIOUnitPage0_t sasioupage0;
1842 pMpi2SasIOUnitPage1_t sasioupage1;
1843 int recv_numbytes;
1844 caddr_t recv_memp, page_memp;
1845 int i, num_phys, start_phy = 0;
1846 int page0_size =
1847 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1848 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1849 int page1_size =
1850 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1851 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1852 uint32_t flags_length;
1853 uint32_t cpdi[MPTSAS_MAX_PHYS];
1854 uint32_t readpage1 = 0, retrypage0 = 0;
1855 uint16_t iocstatus;
1856 uint8_t port_flags, page_number, action;
1857 uint32_t reply_size = 256; /* Big enough for any page */
1858 uint_t state;
1859 int rval = DDI_FAILURE;
1860
1861 /*
1862 * Initialize our "state machine". This is a bit convoluted,
1863 * but it keeps us from having to do the ddi allocations numerous
1864 * times.
1865 */
1866
1867 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1868 ASSERT(mutex_owned(&mpt->m_mutex));
1869 state = IOUC_READ_PAGE0;
1870
1871 /*
1872 * dynamically create a customized dma attribute structure
1873 * that describes mpt's config reply page request structure.
1874 */
1875 recv_dma_attrs = mpt->m_msg_dma_attr;
1876 recv_dma_attrs.dma_attr_sgllen = 1;
1877 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1878
1879 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1880 &recv_dma_handle, &recv_accessp, &recv_memp,
1881 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1882 mptsas_log(mpt, CE_WARN,
1883 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1884 goto cleanup;
1885 }
1886
1887 page_dma_attrs = mpt->m_msg_dma_attr;
1888 page_dma_attrs.dma_attr_sgllen = 1;
1889 page_dma_attrs.dma_attr_granular = reply_size;
1890
1891 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1892 &page_dma_handle, &page_accessp, &page_memp,
1893 reply_size, &page_cookie) == FALSE) {
1894 mptsas_log(mpt, CE_WARN,
1895 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1896 goto cleanup;
1897 }
1898
1899 /*
1900 * Now we cycle through the state machine. Here's what happens:
1901 * 1. Read IO unit page 0 and set phy information
1902 * 2. See if Read IO unit page1 is needed because of port configuration
1903 * 3. Read IO unit page 1 and update phy information.
1904 */
1905
1906 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1907 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1908
1909 while (state != IOUC_DONE) {
1910 switch (state) {
1911 case IOUC_READ_PAGE0:
1912 page_number = 0;
1913 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1914 flags_length = (uint32_t)page0_size;
1915 flags_length |= ((uint32_t)(
1916 MPI2_SGE_FLAGS_LAST_ELEMENT |
1917 MPI2_SGE_FLAGS_END_OF_BUFFER |
1918 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1919 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1920 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
1921 MPI2_SGE_FLAGS_IOC_TO_HOST |
1922 MPI2_SGE_FLAGS_END_OF_LIST) <<
1923 MPI2_SGE_FLAGS_SHIFT);
1924
1925 break;
1926
1927 case IOUC_READ_PAGE1:
1928 page_number = 1;
1929 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1930 flags_length = (uint32_t)page1_size;
1931 flags_length |= ((uint32_t)(
1932 MPI2_SGE_FLAGS_LAST_ELEMENT |
1933 MPI2_SGE_FLAGS_END_OF_BUFFER |
1934 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1935 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1936 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
1937 MPI2_SGE_FLAGS_IOC_TO_HOST |
1938 MPI2_SGE_FLAGS_END_OF_LIST) <<
1939 MPI2_SGE_FLAGS_SHIFT);
1940
1941 break;
1942 default:
1943 break;
1944 }
1945
1946 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
1947 configreply = (pMpi2ConfigReply_t)recv_memp;
1948 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
1949
1950 if (mptsas_send_extended_config_request_msg(mpt,
1951 MPI2_CONFIG_ACTION_PAGE_HEADER,
1952 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
1953 0, page_number, 0, 0, 0, 0)) {
1954 goto cleanup;
1955 }
1956
1960 }
1961
1962 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
1963 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
1964
1965 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1966 mptsas_log(mpt, CE_WARN,
1967 "mptsas_get_sas_io_unit_page_hndshk: read page "
1968 "header iocstatus = 0x%x", iocstatus);
1969 goto cleanup;
1970 }
1971
1972 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
1973 bzero(page_memp, reply_size);
1974 }
1975
1976 if (mptsas_send_extended_config_request_msg(mpt, action,
1977 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
1978 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
1979 ddi_get16(recv_accessp, &configreply->ExtPageLength),
1980 flags_length, page_cookie.dmac_address)) {
1981 goto cleanup;
1982 }
1983
1984 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
1985 recv_accessp)) {
1986 goto cleanup;
1987 }
1988
1989 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
1990 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
1991
1992 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1993 mptsas_log(mpt, CE_WARN,
1994 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
1995 "config failed for action %d, iocstatus = 0x%x",
1996 action, iocstatus);
1997 goto cleanup;
1998 }
1999
2000 switch (state) {
2113
2114 state = IOUC_DONE;
2115 rval = DDI_SUCCESS;
2116 break;
2117 }
2118 }
2119 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2120 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2121 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2122 rval = DDI_FAILURE;
2123 goto cleanup;
2124 }
2125 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2126 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2127 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2128 rval = DDI_FAILURE;
2129 goto cleanup;
2130 }
2131
2132 cleanup:
2133 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2134 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2135 if (rval != DDI_SUCCESS) {
2136 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2137 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2138 }
2139 return (rval);
2140 }
2141
2142 /*
2143 * mptsas_get_manufacture_page5
2144 *
2145 * This function will retrieve the base WWID from the adapter. Since this
2146 * function is only called during the initialization process, use handshaking.
2147 */
2148 int
2149 mptsas_get_manufacture_page5(mptsas_t *mpt)
2150 {
2151 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2152 ddi_dma_cookie_t page_cookie;
2153 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2154 ddi_acc_handle_t recv_accessp, page_accessp;
2155 pMpi2ConfigReply_t configreply;
2156 caddr_t recv_memp, page_memp;
2157 int recv_numbytes;
2158 pMpi2ManufacturingPage5_t m5;
2159 uint32_t flagslength;
2160 int rval = DDI_SUCCESS;
2161 uint_t iocstatus;
2162
2163 MPTSAS_DISABLE_INTR(mpt);
2164
2165 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2166 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2167 rval = DDI_FAILURE;
2168 goto done;
2169 }
2170
2171 /*
2172 * dynamically create a customized dma attribute structure
2173 * that describes the MPT's config reply page request structure.
2174 */
2175 recv_dma_attrs = mpt->m_msg_dma_attr;
2176 recv_dma_attrs.dma_attr_sgllen = 1;
2177 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2178
2179 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2180 &recv_dma_handle, &recv_accessp, &recv_memp,
2181 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2182 goto done;
2183 }
2184
2185 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2186 configreply = (pMpi2ConfigReply_t)recv_memp;
2187 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2188
2189 /*
2190 * get config reply message
2191 */
2192 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2193 recv_accessp)) {
2194 rval = DDI_FAILURE;
2195 goto done;
2196 }
2197
2198 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2199 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2200 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2201 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2202 goto done;
2203 }
2204
2205 /*
2206 * dynamically create a customized dma attribute structure
2207 * that describes the MPT's config page structure.
2208 */
2209 page_dma_attrs = mpt->m_msg_dma_attr;
2210 page_dma_attrs.dma_attr_sgllen = 1;
2211 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2212
2213 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2214 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2215 &page_cookie) == FALSE) {
2216 goto done;
2217 }
2218 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2219 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2220
2221 /*
2222 * Give reply address to IOC to store config page in and send
2223 * config request out.
2224 */
2225
2226 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2227 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2228 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2229 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2230 MPI2_SGE_FLAGS_IOC_TO_HOST |
2231 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2232
2233 if (mptsas_send_config_request_msg(mpt,
2234 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2235 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2236 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2237 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2238 flagslength, page_cookie.dmac_address)) {
2239 rval = DDI_FAILURE;
2240 goto done;
2241 }
2242
2243 /*
2244 * get reply view handshake
2245 */
2246 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2247 recv_accessp)) {
2248 rval = DDI_FAILURE;
2249 goto done;
2250 }
2251
2252 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2253 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2254 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2255 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2256 goto done;
2257 }
2258
2286
2287 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2288 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2289 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2290
2291 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2292 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2293 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2294 rval = DDI_FAILURE;
2295 goto done;
2296 }
2297 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2298 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2299 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2300 rval = DDI_FAILURE;
2301 }
2302 done:
2303 /*
2304 * free up memory
2305 */
2306 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2307 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2308 MPTSAS_ENABLE_INTR(mpt);
2309
2310 return (rval);
2311 }
2312
2313 static int
2314 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2315 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2316 va_list ap)
2317 {
2318 #ifndef __lock_lint
2319 _NOTE(ARGUNUSED(ap))
2320 #endif
2321 pMpi2SasPhyPage0_t sasphypage;
2322 int rval = DDI_SUCCESS;
2323 uint16_t *owner_devhdl, *attached_devhdl;
2324 uint8_t *attached_phy_identify;
2325 uint32_t *attached_phy_info;
2326 uint8_t *programmed_link_rate;
2508 * This function will retrieve the base
2509 * Chip name, Board Name,Board Trace number from the adapter.
2510 * Since this function is only called during the
2511 * initialization process, use handshaking.
2512 */
2513 int
2514 mptsas_get_manufacture_page0(mptsas_t *mpt)
2515 {
2516 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2517 ddi_dma_cookie_t page_cookie;
2518 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2519 ddi_acc_handle_t recv_accessp, page_accessp;
2520 pMpi2ConfigReply_t configreply;
2521 caddr_t recv_memp, page_memp;
2522 int recv_numbytes;
2523 pMpi2ManufacturingPage0_t m0;
2524 uint32_t flagslength;
2525 int rval = DDI_SUCCESS;
2526 uint_t iocstatus;
2527 uint8_t i = 0;
2528
2529 MPTSAS_DISABLE_INTR(mpt);
2530
2531 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2532 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2533 rval = DDI_FAILURE;
2534 goto done;
2535 }
2536
2537 /*
2538 * dynamically create a customized dma attribute structure
2539 * that describes the MPT's config reply page request structure.
2540 */
2541 recv_dma_attrs = mpt->m_msg_dma_attr;
2542 recv_dma_attrs.dma_attr_sgllen = 1;
2543 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2544
2545 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2546 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2547 NULL) == FALSE) {
2548 goto done;
2549 }
2550 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2551 configreply = (pMpi2ConfigReply_t)recv_memp;
2552 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2553
2554 /*
2555 * get config reply message
2556 */
2557 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2558 recv_accessp)) {
2559 rval = DDI_FAILURE;
2560 goto done;
2561 }
2562
2563 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2564 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2565 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2566 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2567 goto done;
2568 }
2569
2570 /*
2571 * dynamically create a customized dma attribute structure
2572 * that describes the MPT's config page structure.
2573 */
2574 page_dma_attrs = mpt->m_msg_dma_attr;
2575 page_dma_attrs.dma_attr_sgllen = 1;
2576 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2577
2578 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2579 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2580 &page_cookie) == FALSE) {
2581 goto done;
2582 }
2583 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2584 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2585
2586 /*
2587 * Give reply address to IOC to store config page in and send
2588 * config request out.
2589 */
2590
2591 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2592 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2593 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2594 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2595 MPI2_SGE_FLAGS_IOC_TO_HOST |
2596 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2597
2598 if (mptsas_send_config_request_msg(mpt,
2599 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2600 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2601 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2602 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2603 flagslength, page_cookie.dmac_address)) {
2604 rval = DDI_FAILURE;
2605 goto done;
2606 }
2607
2608 /*
2609 * get reply view handshake
2610 */
2611 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2612 recv_accessp)) {
2613 rval = DDI_FAILURE;
2614 goto done;
2615 }
2616
2617 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2618 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2619 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2620 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2621 goto done;
2622 }
2623
2656 mpt->m_MANU_page0.BoardTracerNumber[i] =
2657 ddi_get8(page_accessp,
2658 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2659 }
2660
2661 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2662 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2663 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2664 rval = DDI_FAILURE;
2665 goto done;
2666 }
2667 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2668 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2669 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2670 rval = DDI_FAILURE;
2671 }
2672 done:
2673 /*
2674 * free up memory
2675 */
2676 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2677 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2678 MPTSAS_ENABLE_INTR(mpt);
2679
2680 return (rval);
2681 }
|
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
26 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
27 */
28
29 /*
30 * Copyright (c) 2000 to 2010, LSI Corporation.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms of all code within
34 * this file that is exclusively owned by LSI, with or without
35 * modification, is permitted provided that, in addition to the CDDL 1.0
36 * License requirements, the following conditions are met:
37 *
38 * Neither the name of the author nor the names of its contributors may be
39 * used to endorse or promote products derived from this software without
40 * specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
45 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
46 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53 * DAMAGE.
54 */
55
56 /*
57 * mptsas_impl - This file contains all the basic functions for communicating
58 * to MPT based hardware.
59 */
60
61 #if defined(lint) || defined(DEBUG)
62 #define MPTSAS_DEBUG
63 #endif
64
65 /*
66 * standard header files
67 */
68 #include <sys/note.h>
69 #include <sys/scsi/scsi.h>
70 #include <sys/pci.h>
71
72 #pragma pack(1)
73 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
74 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
75 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
76 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
77 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
78 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h>
79 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
80 #pragma pack()
81
82 /*
83 * private header files.
84 */
85 #include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
86 #include <sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h>
87
88 /*
89 * FMA header files.
90 */
91 #include <sys/fm/io/ddi.h>
92
93 #if defined(MPTSAS_DEBUG)
94 extern uint32_t mptsas_debug_flags;
95 extern uint32_t mptsas_dbglog_imask;
96 #endif
97
98 /*
99 * prototypes
100 */
101 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
102 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
103 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
104 struct mptsas_cmd *cmd);
105
106 /*
107 * add ioc evnet cmd into the queue
108 */
109 static void
110 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
111 {
112 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
113 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
114 mpt->m_ioc_event_cmdq = cmd;
115 } else {
191 } else {
192 /*
193 * it's not ack cmd, so continue to check next one
194 */
195
196 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
197 ioc_cmd = ioc_cmd->m_event_linkp;
198 }
199
200 }
201 }
202
203 void
204 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
205 {
206 pMpi2ConfigRequest_t request;
207 pMpi2SGESimple64_t sge;
208 struct scsi_pkt *pkt = cmd->cmd_pkt;
209 mptsas_config_request_t *config = pkt->pkt_ha_private;
210 uint8_t direction;
211 uint32_t length, flagslength;
212 uint64_t request_desc;
213
214 ASSERT(mutex_owned(&mpt->m_mutex));
215
216 /*
217 * Point to the correct message and clear it as well as the global
218 * config page memory.
219 */
220 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
221 (mpt->m_req_frame_size * cmd->cmd_slot));
222 bzero(request, mpt->m_req_frame_size);
223
224 /*
225 * Form the request message.
226 */
227 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
228 MPI2_FUNCTION_CONFIG);
229 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
230 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
231 length = 0;
232 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
246 config->ext_page_type);
247 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
248 config->ext_page_length);
249 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
250 config->page_type);
251 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
252 config->page_length);
253 ddi_put8(mpt->m_acc_req_frame_hdl,
254 &request->Header.PageVersion, config->page_version);
255 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
256 MPI2_CONFIG_PAGETYPE_EXTENDED) {
257 length = config->ext_page_length * 4;
258 } else {
259 length = config->page_length * 4;
260 }
261
262 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
263 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
264 }
265 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
266 (uint32_t)(cmd->cmd_dma_addr&0xfffffffful));
267 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
268 (uint32_t)(cmd->cmd_dma_addr >> 32));
269 }
270 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
271 config->page_number);
272 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
273 config->page_address);
274 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
275 MPI2_SGE_FLAGS_END_OF_BUFFER |
276 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
277 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
278 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
279 direction |
280 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
281 flagslength |= length;
282 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
283
284 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
285 DDI_DMA_SYNC_FORDEV);
286 request_desc = (cmd->cmd_slot << 16) +
287 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
288 cmd->cmd_rfm = NULL;
289 MPTSAS_START_CMD(mpt, request_desc);
290 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
291 DDI_SUCCESS) ||
292 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
293 DDI_SUCCESS)) {
294 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
295 }
296 }
297
298 int
299 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
300 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
301 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
302 {
303 va_list ap;
304 ddi_dma_attr_t attrs;
305 ddi_dma_cookie_t cookie;
306 ddi_acc_handle_t accessp;
307 size_t len = 0;
308 mptsas_config_request_t config;
309 int rval = DDI_SUCCESS, config_flags = 0;
310 mptsas_cmd_t *cmd;
311 struct scsi_pkt *pkt;
312 pMpi2ConfigReply_t reply;
313 uint16_t iocstatus = 0;
314 uint32_t iocloginfo;
315 caddr_t page_memp;
316 boolean_t free_dma = B_FALSE;
317
318 va_start(ap, callback);
319 ASSERT(mutex_owned(&mpt->m_mutex));
320
321 /*
322 * Get a command from the pool.
323 */
324 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
325 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
326 "page request");
327 rval = DDI_FAILURE;
328 goto page_done;
329 }
330 config_flags |= MPTSAS_REQUEST_POOL_CMD;
331
332 bzero((caddr_t)cmd, sizeof (*cmd));
333 bzero((caddr_t)pkt, scsi_pkt_size());
334 bzero((caddr_t)&config, sizeof (config));
335
336 /*
379 }
380
381 /*
382 * Check if the header request completed without timing out
383 */
384 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
385 mptsas_log(mpt, CE_WARN, "config header request timeout");
386 rval = DDI_FAILURE;
387 goto page_done;
388 }
389
390 /*
391 * cmd_rfm points to the reply message if a reply was given. Check the
392 * IOCStatus to make sure everything went OK with the header request.
393 */
394 if (cmd->cmd_rfm) {
395 config_flags |= MPTSAS_ADDRESS_REPLY;
396 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
397 DDI_DMA_SYNC_FORCPU);
398 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
399 - (mpt->m_reply_frame_dma_addr&0xfffffffful)));
400 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
401 &reply->Header.PageType);
402 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
403 &reply->Header.PageNumber);
404 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
405 &reply->Header.PageLength);
406 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
407 &reply->Header.PageVersion);
408 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
409 &reply->ExtPageType);
410 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
411 &reply->ExtPageLength);
412
413 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
414 &reply->IOCStatus);
415 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
416 &reply->IOCLogInfo);
417
418 if (iocstatus) {
419 NDBG13(("mptsas_access_config_page header: "
453 mpt->m_free_index = 0;
454 }
455 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
456 mpt->m_free_index);
457 config_flags &= (~MPTSAS_ADDRESS_REPLY);
458 }
459
460 /*
461 * Allocate DMA buffer here. Store the info regarding this buffer in
462 * the cmd struct so that it can be used for this specific command and
463 * de-allocated after the command completes. The size of the reply
464 * will not be larger than the reply frame size.
465 */
466 attrs = mpt->m_msg_dma_attr;
467 attrs.dma_attr_sgllen = 1;
468 attrs.dma_attr_granular = (uint32_t)len;
469
470 if (mptsas_dma_addr_create(mpt, attrs,
471 &cmd->cmd_dmahandle, &accessp, &page_memp,
472 len, &cookie) == FALSE) {
473 mptsas_log(mpt, CE_WARN,
474 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
475 rval = DDI_FAILURE;
476 goto page_done;
477 }
478 /* NOW we can safely call mptsas_dma_addr_destroy(). */
479 free_dma = B_TRUE;
480
481 cmd->cmd_dma_addr = cookie.dmac_laddress;
482 bzero(page_memp, len);
483
484 /*
485 * Save the data for this request to be used in the call to start the
486 * config page read
487 */
488 config.action = action;
489 config.page_address = page_address;
490
491 /*
492 * Re-use the cmd that was used to get the header. Reset some of the
493 * values.
494 */
495 bzero((caddr_t)pkt, scsi_pkt_size());
496 pkt->pkt_ha_private = (opaque_t)&config;
497 pkt->pkt_flags = FLAG_HEAD;
498 pkt->pkt_time = 60;
499 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
500
524 * Check if the request completed without timing out
525 */
526 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
527 mptsas_log(mpt, CE_WARN, "config page request timeout");
528 rval = DDI_FAILURE;
529 goto page_done;
530 }
531
532 /*
533 * cmd_rfm points to the reply message if a reply was given. The reply
534 * frame and the config page are returned from this function in the
535 * param list.
536 */
537 if (cmd->cmd_rfm) {
538 config_flags |= MPTSAS_ADDRESS_REPLY;
539 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
540 DDI_DMA_SYNC_FORCPU);
541 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
542 DDI_DMA_SYNC_FORCPU);
543 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
544 - (mpt->m_reply_frame_dma_addr&0xfffffffful)));
545 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
546 &reply->IOCStatus);
547 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
548 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
549 &reply->IOCLogInfo);
550 }
551
552 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
553 rval = DDI_FAILURE;
554 goto page_done;
555 }
556
557 mptsas_fma_check(mpt, cmd);
558 /*
559 * Check the DMA/ACC handles and then free the DMA buffer.
560 */
561 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
562 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
563 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
564 rval = DDI_FAILURE;
578 page_done:
579 va_end(ap);
580 /*
581 * Put the reply frame back on the free queue, increment the free
582 * index, and write the new index to the free index register. But only
583 * if this reply is an ADDRESS reply.
584 */
585 if (config_flags & MPTSAS_ADDRESS_REPLY) {
586 ddi_put32(mpt->m_acc_free_queue_hdl,
587 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
588 cmd->cmd_rfm);
589 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
590 DDI_DMA_SYNC_FORDEV);
591 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
592 mpt->m_free_index = 0;
593 }
594 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
595 mpt->m_free_index);
596 }
597
598 if (free_dma)
599 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
600
601 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
602 mptsas_remove_cmd(mpt, cmd);
603 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
604 }
605 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
606 mptsas_return_to_pool(mpt, cmd);
607
608 if (config_flags & MPTSAS_CMD_TIMEOUT) {
609 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
610 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
611 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
612 }
613 }
614
615 return (rval);
616 }
617
618 int
619 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
620 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
621 uint8_t pagelength, uint32_t SGEflagslength, uint64_t SGEaddress)
622 {
623 pMpi2ConfigRequest_t config;
624 int send_numbytes;
625
626 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
627 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
628 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
629 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
630 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
631 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
632 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
633 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
634 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
635 ddi_put32(mpt->m_hshk_acc_hdl,
636 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
637 ddi_put32(mpt->m_hshk_acc_hdl,
638 &config->PageBufferSGE.MpiSimple.u.Address64.Low,
639 SGEaddress&0xfffffffful);
640 ddi_put32(mpt->m_hshk_acc_hdl,
641 &config->PageBufferSGE.MpiSimple.u.Address64.High,
642 SGEaddress >> 32);
643 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
644
645 /*
646 * Post message via handshake
647 */
648 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
649 mpt->m_hshk_acc_hdl)) {
650 return (-1);
651 }
652 return (0);
653 }
654
655 int
656 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
657 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
658 uint8_t pageversion, uint16_t extpagelength,
659 uint32_t SGEflagslength, uint64_t SGEaddress)
660 {
661 pMpi2ConfigRequest_t config;
662 int send_numbytes;
663
664 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
665 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
666 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
667 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
668 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
669 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
670 MPI2_CONFIG_PAGETYPE_EXTENDED);
671 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
672 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
673 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
674 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
675 ddi_put32(mpt->m_hshk_acc_hdl,
676 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
677 ddi_put32(mpt->m_hshk_acc_hdl,
678 &config->PageBufferSGE.MpiSimple.u.Address64.Low,
679 SGEaddress&0xfffffffful);
680 ddi_put32(mpt->m_hshk_acc_hdl,
681 &config->PageBufferSGE.MpiSimple.u.Address64.High,
682 SGEaddress >> 32);
683 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
684
685 /*
686 * Post message via handshake
687 */
688 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
689 mpt->m_hshk_acc_hdl)) {
690 return (-1);
691 }
692 return (0);
693 }
694
695 int
696 mptsas_ioc_wait_for_response(mptsas_t *mpt)
697 {
698 int polls = 0;
699
700 while ((ddi_get32(mpt->m_datap,
701 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
702 drv_usecwait(1000);
1090 * priority queue with its limit and the controller will reply as they are
1091 * completed. This way, we don't have to poll for one reply at a time.
1092 * Think about enhancing this later.
1093 */
1094 int
1095 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1096 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1097 {
1098 /*
1099 * In order to avoid allocating variables on the stack,
1100 * we make use of the pre-existing mptsas_cmd_t and
1101 * scsi_pkt which are included in the mptsas_t which
1102 * is passed to this routine.
1103 */
1104
1105 pMpi2SCSITaskManagementRequest_t task;
1106 int rval = FALSE;
1107 mptsas_cmd_t *cmd;
1108 struct scsi_pkt *pkt;
1109 mptsas_slots_t *slots = mpt->m_active;
1110 uint32_t i;
1111 uint64_t request_desc;
1112 pMPI2DefaultReply_t reply_msg;
1113
1114 /*
1115 * Can't start another task management routine.
1116 */
1117 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1118 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1119 " command at a time\n");
1120 return (FALSE);
1121 }
1122
1123 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1124 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1125
1126 bzero((caddr_t)cmd, sizeof (*cmd));
1127 bzero((caddr_t)pkt, scsi_pkt_size());
1128
1129 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1130 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1131 pkt->pkt_ha_private = (opaque_t)cmd;
1147 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1148 (mpt->m_req_frame_size * cmd->cmd_slot));
1149 bzero(task, mpt->m_req_frame_size);
1150
1151 /*
1152 * form message for requested task
1153 */
1154 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1155 MPI2_FUNCTION_SCSI_TASK_MGMT);
1156
1157 /*
1158 * Set the task type
1159 */
1160 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1161
1162 /*
1163 * Send TM request using High Priority Queue.
1164 */
1165 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1166 DDI_DMA_SYNC_FORDEV);
1167 request_desc = (cmd->cmd_slot << 16) +
1168 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1169 MPTSAS_START_CMD(mpt, request_desc);
1170 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1171
1172 if (pkt->pkt_reason == CMD_INCOMPLETE)
1173 rval = FALSE;
1174
1175 /*
1176 * If a reply frame was used and there is a reply buffer to copy the
1177 * reply data into, copy it. If this fails, log a message, but don't
1178 * fail the TM request.
1179 */
1180 if (cmd->cmd_rfm && reply) {
1181 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1182 DDI_DMA_SYNC_FORCPU);
1183 reply_msg = (pMPI2DefaultReply_t)
1184 (mpt->m_reply_frame + (cmd->cmd_rfm -
1185 (mpt->m_reply_frame_dma_addr&0xfffffffful)));
1186 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1187 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1188 }
1189 mutex_exit(&mpt->m_mutex);
1190 for (i = 0; i < reply_size; i++) {
1191 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1192 mode)) {
1193 mptsas_log(mpt, CE_WARN, "failed to copy out "
1194 "reply data for TM request");
1195 break;
1196 }
1197 }
1198 mutex_enter(&mpt->m_mutex);
1199 }
1200
1201 /*
1202 * clear the TM slot before returning
1203 */
1204 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1205
1206 /*
1207 * If we lost our task management command
1208 * we need to reset the ioc
1209 */
1210 if (rval == FALSE) {
1211 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1212 "try to reset ioc to recovery!");
1213 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1214 if (mptsas_restart_ioc(mpt)) {
1215 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1216 rval = FAILED;
1217 }
1218 }
1219
1220 return (rval);
1221 }
1222
1223 /*
1224 * Complete firmware download frame for v2.0 cards.
1225 */
1226 static void
1227 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1228 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1229 ddi_dma_cookie_t flsh_cookie)
1230 {
1231 pMpi2FWDownloadTCSGE_t tcsge;
1232 pMpi2SGESimple64_t sge;
1233 uint32_t flagslength;
1234
1235 ddi_put8(acc_hdl, &fwdownload->Function,
1236 MPI2_FUNCTION_FW_DOWNLOAD);
1237 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1238 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1239 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1240 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1241
1242 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1243 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1244 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1245 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1246 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1247 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1248
1249 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1250 flagslength = size;
1251 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1252 MPI2_SGE_FLAGS_END_OF_BUFFER |
1253 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1254 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1255 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1256 MPI2_SGE_FLAGS_HOST_TO_IOC |
1257 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1258 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1259 ddi_put32(acc_hdl, &sge->Address.Low,
1260 flsh_cookie.dmac_address);
1261 ddi_put32(acc_hdl, &sge->Address.High,
1262 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1263 }
1264
1265 /*
1266 * Complete firmware download frame for v2.5 cards.
1267 */
1268 static void
1269 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1270 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1271 ddi_dma_cookie_t flsh_cookie)
1272 {
1273 pMpi2IeeeSgeSimple64_t sge;
1274 uint8_t flags;
1275
1276 ddi_put8(acc_hdl, &fwdownload->Function,
1277 MPI2_FUNCTION_FW_DOWNLOAD);
1278 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1279 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1280 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1281 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1282
1283 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1284 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1285
1286 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1287 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1288 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1289 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1290 ddi_put8(acc_hdl, &sge->Flags, flags);
1291 ddi_put32(acc_hdl, &sge->Length, size);
1292 ddi_put32(acc_hdl, &sge->Address.Low,
1293 flsh_cookie.dmac_address);
1294 ddi_put32(acc_hdl, &sge->Address.High,
1295 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1296 }
1297
1298 static int mptsas_enable_mpi25_flashupdate = 0;
1299
1300 int
1301 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1302 uint8_t type, int mode)
1303 {
1304
1305 /*
1306 * In order to avoid allocating variables on the stack,
1307 * we make use of the pre-existing mptsas_cmd_t and
1308 * scsi_pkt which are included in the mptsas_t which
1309 * is passed to this routine.
1310 */
1311
1312 ddi_dma_attr_t flsh_dma_attrs;
1313 ddi_dma_cookie_t flsh_cookie;
1314 ddi_dma_handle_t flsh_dma_handle;
1315 ddi_acc_handle_t flsh_accessp;
1316 caddr_t memp, flsh_memp;
1317 mptsas_cmd_t *cmd;
1318 struct scsi_pkt *pkt;
1319 int i;
1320 int rvalue = 0;
1321 uint64_t request_desc;
1322
1323 if (mpt->m_MPI25) {
1324 /*
1325 * The code is there but not tested yet.
1326 * User has to know there are risks here.
1327 */
1328 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1329 "Updating firmware through MPI 2.5 has not been "
1330 "tested yet!\n"
1331 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1332 if (!mptsas_enable_mpi25_flashupdate)
1333 return (-1);
1334 }
1335
1336 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1337 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1338 "failed. event ack command pool is full\n");
1339 return (rvalue);
1340 }
1341
1342 bzero((caddr_t)cmd, sizeof (*cmd));
1343 bzero((caddr_t)pkt, scsi_pkt_size());
1344 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1345
1346 /*
1347 * dynamically create a customized dma attribute structure
1348 * that describes the flash file.
1349 */
1350 flsh_dma_attrs = mpt->m_msg_dma_attr;
1351 flsh_dma_attrs.dma_attr_sgllen = 1;
1352
1353 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1354 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1375 pkt->pkt_time = 60;
1376 cmd->cmd_pkt = pkt;
1377 cmd->cmd_scblen = 1;
1378 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1379
1380 /*
1381 * Save the command in a slot
1382 */
1383 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1384 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1385 mptsas_return_to_pool(mpt, cmd);
1386 return (-1);
1387 }
1388
1389 /*
1390 * Fill in fw download message
1391 */
1392 ASSERT(cmd->cmd_slot != 0);
1393 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1394 bzero(memp, mpt->m_req_frame_size);
1395
1396 if (mpt->m_MPI25)
1397 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1398 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1399 else
1400 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1401 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1402
1403 /*
1404 * Start command
1405 */
1406 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1407 DDI_DMA_SYNC_FORDEV);
1408 request_desc = (cmd->cmd_slot << 16) +
1409 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1410 cmd->cmd_rfm = NULL;
1411 MPTSAS_START_CMD(mpt, request_desc);
1412
1413 rvalue = 0;
1414 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1415 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1416 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1417 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1418 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1419 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1420 }
1421 rvalue = -1;
1422 }
1423 mptsas_remove_cmd(mpt, cmd);
1424 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1425
1426 return (rvalue);
1427 }
1428
1429 static int
1430 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1431 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1432 va_list ap)
1433 {
1434 #ifndef __lock_lint
1435 _NOTE(ARGUNUSED(ap))
1436 #endif
1437 pMpi2SasDevicePage0_t sasdevpage;
1438 int rval = DDI_SUCCESS, i;
1439 uint8_t *sas_addr = NULL;
1440 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1441 uint16_t *devhdl, *bay_num, *enclosure;
1442 uint64_t *sas_wwn;
1443 uint32_t *dev_info;
1444 uint8_t *physport, *phynum;
1445 uint16_t *pdevhdl, *io_flags;
1446 uint32_t page_address;
1447
1448 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1449 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1450 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1451 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1452 iocstatus, iocloginfo);
1453 rval = DDI_FAILURE;
1454 return (rval);
1455 }
1456 page_address = va_arg(ap, uint32_t);
1457 /*
1458 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1459 * are no more pages. If everything is OK up to this point but the
1460 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1461 * signal that device traversal is complete.
1462 */
1463 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1464 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1465 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1466 mpt->m_done_traverse_dev = 1;
1467 }
1468 rval = DDI_FAILURE;
1469 return (rval);
1470 }
1471 devhdl = va_arg(ap, uint16_t *);
1472 sas_wwn = va_arg(ap, uint64_t *);
1473 dev_info = va_arg(ap, uint32_t *);
1474 physport = va_arg(ap, uint8_t *);
1475 phynum = va_arg(ap, uint8_t *);
1476 pdevhdl = va_arg(ap, uint16_t *);
1477 bay_num = va_arg(ap, uint16_t *);
1478 enclosure = va_arg(ap, uint16_t *);
1479 io_flags = va_arg(ap, uint16_t *);
1480
1481 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1482
1483 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1484 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1485 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1486 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1487 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1488 }
1489 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1490 *sas_wwn = LE_64(*sas_wwn);
1491 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1492 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1493 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1494 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1495 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1496 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1497
1498 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1499 /*
1500 * Leave a messages about FP cabability in the log.
1501 */
1502 mptsas_log(mpt, CE_CONT,
1503 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1504 (*io_flags &
1505 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1506 " and Enabled":" but Disabled");
1507 }
1508
1509 return (rval);
1510 }
1511
1512 /*
1513 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1514 * info and SAS address.
1515 */
1516 int
1517 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1518 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1519 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1520 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1521 {
1522 int rval = DDI_SUCCESS;
1523
1524 ASSERT(mutex_owned(&mpt->m_mutex));
1525
1526 /*
1527 * Get the header and config page. reply contains the reply frame,
1528 * which holds status info for the request.
1529 */
1530 rval = mptsas_access_config_page(mpt,
1531 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1532 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1533 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1534 dev_info, physport, phynum, pdev_handle,
1535 bay_num, enclosure, io_flags);
1536
1537 return (rval);
1538 }
1539
1540 static int
1541 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1542 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1543 va_list ap)
1544 {
1545 #ifndef __lock_lint
1546 _NOTE(ARGUNUSED(ap))
1547 #endif
1548 pMpi2ExpanderPage0_t expddevpage;
1549 int rval = DDI_SUCCESS, i;
1550 uint8_t *sas_addr = NULL;
1551 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1552 uint16_t *devhdl;
1553 uint64_t *sas_wwn;
1554 uint8_t physport;
1555 mptsas_phymask_t *phymask;
1938 pMpi2ConfigReply_t configreply;
1939 pMpi2SasIOUnitPage0_t sasioupage0;
1940 pMpi2SasIOUnitPage1_t sasioupage1;
1941 int recv_numbytes;
1942 caddr_t recv_memp, page_memp;
1943 int i, num_phys, start_phy = 0;
1944 int page0_size =
1945 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1946 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1947 int page1_size =
1948 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1949 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1950 uint32_t flags_length;
1951 uint32_t cpdi[MPTSAS_MAX_PHYS];
1952 uint32_t readpage1 = 0, retrypage0 = 0;
1953 uint16_t iocstatus;
1954 uint8_t port_flags, page_number, action;
1955 uint32_t reply_size = 256; /* Big enough for any page */
1956 uint_t state;
1957 int rval = DDI_FAILURE;
1958 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1959
1960 /*
1961 * Initialize our "state machine". This is a bit convoluted,
1962 * but it keeps us from having to do the ddi allocations numerous
1963 * times.
1964 */
1965
1966 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1967 ASSERT(mutex_owned(&mpt->m_mutex));
1968 state = IOUC_READ_PAGE0;
1969
1970 /*
1971 * dynamically create a customized dma attribute structure
1972 * that describes mpt's config reply page request structure.
1973 */
1974 recv_dma_attrs = mpt->m_msg_dma_attr;
1975 recv_dma_attrs.dma_attr_sgllen = 1;
1976 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1977
1978 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1979 &recv_dma_handle, &recv_accessp, &recv_memp,
1980 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1981 mptsas_log(mpt, CE_WARN,
1982 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1983 goto cleanup;
1984 }
1985 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1986 free_recv = B_TRUE;
1987
1988 page_dma_attrs = mpt->m_msg_dma_attr;
1989 page_dma_attrs.dma_attr_sgllen = 1;
1990 page_dma_attrs.dma_attr_granular = reply_size;
1991
1992 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1993 &page_dma_handle, &page_accessp, &page_memp,
1994 reply_size, &page_cookie) == FALSE) {
1995 mptsas_log(mpt, CE_WARN,
1996 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1997 goto cleanup;
1998 }
1999 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2000 free_page = B_TRUE;
2001
2002 /*
2003 * Now we cycle through the state machine. Here's what happens:
2004 * 1. Read IO unit page 0 and set phy information
2005 * 2. See if Read IO unit page1 is needed because of port configuration
2006 * 3. Read IO unit page 1 and update phy information.
2007 */
2008
2009 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
2010 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2011
2012 while (state != IOUC_DONE) {
2013 switch (state) {
2014 case IOUC_READ_PAGE0:
2015 page_number = 0;
2016 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2017 flags_length = (uint32_t)page0_size;
2018 flags_length |= ((uint32_t)(
2019 MPI2_SGE_FLAGS_LAST_ELEMENT |
2020 MPI2_SGE_FLAGS_END_OF_BUFFER |
2021 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2022 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2023 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2024 MPI2_SGE_FLAGS_IOC_TO_HOST |
2025 MPI2_SGE_FLAGS_END_OF_LIST) <<
2026 MPI2_SGE_FLAGS_SHIFT);
2027
2028 break;
2029
2030 case IOUC_READ_PAGE1:
2031 page_number = 1;
2032 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2033 flags_length = (uint32_t)page1_size;
2034 flags_length |= ((uint32_t)(
2035 MPI2_SGE_FLAGS_LAST_ELEMENT |
2036 MPI2_SGE_FLAGS_END_OF_BUFFER |
2037 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2038 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2039 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2040 MPI2_SGE_FLAGS_IOC_TO_HOST |
2041 MPI2_SGE_FLAGS_END_OF_LIST) <<
2042 MPI2_SGE_FLAGS_SHIFT);
2043
2044 break;
2045 default:
2046 break;
2047 }
2048
2049 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2050 configreply = (pMpi2ConfigReply_t)recv_memp;
2051 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2052
2053 if (mptsas_send_extended_config_request_msg(mpt,
2054 MPI2_CONFIG_ACTION_PAGE_HEADER,
2055 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2056 0, page_number, 0, 0, 0, 0)) {
2057 goto cleanup;
2058 }
2059
2063 }
2064
2065 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2066 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2067
2068 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2069 mptsas_log(mpt, CE_WARN,
2070 "mptsas_get_sas_io_unit_page_hndshk: read page "
2071 "header iocstatus = 0x%x", iocstatus);
2072 goto cleanup;
2073 }
2074
2075 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2076 bzero(page_memp, reply_size);
2077 }
2078
2079 if (mptsas_send_extended_config_request_msg(mpt, action,
2080 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2081 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2082 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2083 flags_length, page_cookie.dmac_laddress)) {
2084 goto cleanup;
2085 }
2086
2087 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2088 recv_accessp)) {
2089 goto cleanup;
2090 }
2091
2092 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2093 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2094
2095 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2096 mptsas_log(mpt, CE_WARN,
2097 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2098 "config failed for action %d, iocstatus = 0x%x",
2099 action, iocstatus);
2100 goto cleanup;
2101 }
2102
2103 switch (state) {
2216
2217 state = IOUC_DONE;
2218 rval = DDI_SUCCESS;
2219 break;
2220 }
2221 }
2222 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2223 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2224 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2225 rval = DDI_FAILURE;
2226 goto cleanup;
2227 }
2228 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2229 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2230 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2231 rval = DDI_FAILURE;
2232 goto cleanup;
2233 }
2234
2235 cleanup:
2236 if (free_recv)
2237 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2238 if (free_page)
2239 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2240 if (rval != DDI_SUCCESS) {
2241 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2242 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2243 }
2244 return (rval);
2245 }
2246
2247 /*
2248 * mptsas_get_manufacture_page5
2249 *
2250 * This function will retrieve the base WWID from the adapter. Since this
2251 * function is only called during the initialization process, use handshaking.
2252 */
2253 int
2254 mptsas_get_manufacture_page5(mptsas_t *mpt)
2255 {
2256 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2257 ddi_dma_cookie_t page_cookie;
2258 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2259 ddi_acc_handle_t recv_accessp, page_accessp;
2260 pMpi2ConfigReply_t configreply;
2261 caddr_t recv_memp, page_memp;
2262 int recv_numbytes;
2263 pMpi2ManufacturingPage5_t m5;
2264 uint32_t flagslength;
2265 int rval = DDI_SUCCESS;
2266 uint_t iocstatus;
2267 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2268
2269 MPTSAS_DISABLE_INTR(mpt);
2270
2271 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2272 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2273 rval = DDI_FAILURE;
2274 goto done;
2275 }
2276
2277 /*
2278 * dynamically create a customized dma attribute structure
2279 * that describes the MPT's config reply page request structure.
2280 */
2281 recv_dma_attrs = mpt->m_msg_dma_attr;
2282 recv_dma_attrs.dma_attr_sgllen = 1;
2283 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2284
2285 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2286 &recv_dma_handle, &recv_accessp, &recv_memp,
2287 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2288 rval = DDI_FAILURE;
2289 goto done;
2290 }
2291 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2292 free_recv = B_TRUE;
2293
2294 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2295 configreply = (pMpi2ConfigReply_t)recv_memp;
2296 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2297
2298 /*
2299 * get config reply message
2300 */
2301 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2302 recv_accessp)) {
2303 rval = DDI_FAILURE;
2304 goto done;
2305 }
2306
2307 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2308 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2309 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2310 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2311 goto done;
2312 }
2313
2314 /*
2315 * dynamically create a customized dma attribute structure
2316 * that describes the MPT's config page structure.
2317 */
2318 page_dma_attrs = mpt->m_msg_dma_attr;
2319 page_dma_attrs.dma_attr_sgllen = 1;
2320 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2321
2322 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2323 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2324 &page_cookie) == FALSE) {
2325 rval = DDI_FAILURE;
2326 goto done;
2327 }
2328 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2329 free_page = B_TRUE;
2330
2331 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2332 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2333 NDBG20(("mptsas_get_manufacture_page5: paddr 0x%x%08x",
2334 (uint32_t)(page_cookie.dmac_laddress>>32),
2335 (uint32_t)(page_cookie.dmac_laddress&0xfffffffful)));
2336
2337 /*
2338 * Give reply address to IOC to store config page in and send
2339 * config request out.
2340 */
2341
2342 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2343 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2344 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2345 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2346 MPI2_SGE_FLAGS_IOC_TO_HOST |
2347 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2348
2349 if (mptsas_send_config_request_msg(mpt,
2350 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2351 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2352 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2353 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2354 flagslength, page_cookie.dmac_laddress)) {
2355 rval = DDI_FAILURE;
2356 goto done;
2357 }
2358
2359 /*
2360 * get reply view handshake
2361 */
2362 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2363 recv_accessp)) {
2364 rval = DDI_FAILURE;
2365 goto done;
2366 }
2367
2368 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2369 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2370 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2371 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2372 goto done;
2373 }
2374
2402
2403 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2404 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2405 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2406
2407 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2408 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2409 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2410 rval = DDI_FAILURE;
2411 goto done;
2412 }
2413 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2414 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2415 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2416 rval = DDI_FAILURE;
2417 }
2418 done:
2419 /*
2420 * free up memory
2421 */
2422 if (free_recv)
2423 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2424 if (free_page)
2425 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2426 MPTSAS_ENABLE_INTR(mpt);
2427
2428 return (rval);
2429 }
2430
2431 static int
2432 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2433 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2434 va_list ap)
2435 {
2436 #ifndef __lock_lint
2437 _NOTE(ARGUNUSED(ap))
2438 #endif
2439 pMpi2SasPhyPage0_t sasphypage;
2440 int rval = DDI_SUCCESS;
2441 uint16_t *owner_devhdl, *attached_devhdl;
2442 uint8_t *attached_phy_identify;
2443 uint32_t *attached_phy_info;
2444 uint8_t *programmed_link_rate;
2626 * This function will retrieve the base
2627 * Chip name, Board Name,Board Trace number from the adapter.
2628 * Since this function is only called during the
2629 * initialization process, use handshaking.
2630 */
2631 int
2632 mptsas_get_manufacture_page0(mptsas_t *mpt)
2633 {
2634 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2635 ddi_dma_cookie_t page_cookie;
2636 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2637 ddi_acc_handle_t recv_accessp, page_accessp;
2638 pMpi2ConfigReply_t configreply;
2639 caddr_t recv_memp, page_memp;
2640 int recv_numbytes;
2641 pMpi2ManufacturingPage0_t m0;
2642 uint32_t flagslength;
2643 int rval = DDI_SUCCESS;
2644 uint_t iocstatus;
2645 uint8_t i = 0;
2646 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2647
2648 MPTSAS_DISABLE_INTR(mpt);
2649
2650 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2651 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2652 rval = DDI_FAILURE;
2653 goto done;
2654 }
2655
2656 /*
2657 * dynamically create a customized dma attribute structure
2658 * that describes the MPT's config reply page request structure.
2659 */
2660 recv_dma_attrs = mpt->m_msg_dma_attr;
2661 recv_dma_attrs.dma_attr_sgllen = 1;
2662 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2663
2664 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2665 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2666 NULL) == FALSE) {
2667 rval = DDI_FAILURE;
2668 goto done;
2669 }
2670 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2671 free_recv = B_TRUE;
2672
2673 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2674 configreply = (pMpi2ConfigReply_t)recv_memp;
2675 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2676
2677 /*
2678 * get config reply message
2679 */
2680 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2681 recv_accessp)) {
2682 rval = DDI_FAILURE;
2683 goto done;
2684 }
2685
2686 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2687 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2688 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2689 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2690 goto done;
2691 }
2692
2693 /*
2694 * dynamically create a customized dma attribute structure
2695 * that describes the MPT's config page structure.
2696 */
2697 page_dma_attrs = mpt->m_msg_dma_attr;
2698 page_dma_attrs.dma_attr_sgllen = 1;
2699 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2700
2701 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2702 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2703 &page_cookie) == FALSE) {
2704 rval = DDI_FAILURE;
2705 goto done;
2706 }
2707 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2708 free_page = B_TRUE;
2709
2710 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2711 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2712
2713 /*
2714 * Give reply address to IOC to store config page in and send
2715 * config request out.
2716 */
2717
2718 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2719 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2720 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2721 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
2722 MPI2_SGE_FLAGS_IOC_TO_HOST |
2723 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2724
2725 if (mptsas_send_config_request_msg(mpt,
2726 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2727 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2728 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2729 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2730 flagslength, page_cookie.dmac_laddress)) {
2731 rval = DDI_FAILURE;
2732 goto done;
2733 }
2734
2735 /*
2736 * get reply view handshake
2737 */
2738 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2739 recv_accessp)) {
2740 rval = DDI_FAILURE;
2741 goto done;
2742 }
2743
2744 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2745 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2746 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2747 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2748 goto done;
2749 }
2750
2783 mpt->m_MANU_page0.BoardTracerNumber[i] =
2784 ddi_get8(page_accessp,
2785 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2786 }
2787
2788 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2789 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2790 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2791 rval = DDI_FAILURE;
2792 goto done;
2793 }
2794 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2795 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2796 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2797 rval = DDI_FAILURE;
2798 }
2799 done:
2800 /*
2801 * free up memory
2802 */
2803 if (free_recv)
2804 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2805 if (free_page)
2806 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2807 MPTSAS_ENABLE_INTR(mpt);
2808
2809 return (rval);
2810 }
|