4546 mpt_sas needs enhancing to support LSI MPI2.5
[unleashed.git] / usr / src / uts / common / io / scsi / adapters / mpt_sas / mptsas_impl.c
blob5d34d65a5e4f5c9caf23895d326f22fdf2f8d8ce
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
26 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
30 * Copyright (c) 2000 to 2010, LSI Corporation.
31 * All rights reserved.
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:
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.
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,
47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
48 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
49 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
50 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53 * DAMAGE.
57 * mptsas_impl - This file contains all the basic functions for communicating
58 * to MPT based hardware.
61 #if defined(lint) || defined(DEBUG)
62 #define MPTSAS_DEBUG
63 #endif
66 * standard header files
68 #include <sys/note.h>
69 #include <sys/scsi/scsi.h>
70 #include <sys/pci.h>
72 #pragma pack(1)
73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
80 #pragma pack()
83 * private header files.
85 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
86 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
89 * FMA header files.
91 #include <sys/fm/io/ddi.h>
93 #if defined(MPTSAS_DEBUG)
94 extern uint32_t mptsas_debug_flags;
95 #endif
98 * prototypes
100 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
101 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
102 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
103 struct mptsas_cmd *cmd);
106 * add ioc evnet cmd into the queue
108 static void
109 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
111 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
112 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
113 mpt->m_ioc_event_cmdq = cmd;
114 } else {
115 cmd->m_event_linkp = NULL;
116 *(mpt->m_ioc_event_cmdtail) = cmd;
117 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
122 * remove specified cmd from the ioc event queue
124 static void
125 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
127 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
128 if (prev == cmd) {
129 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
130 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
132 cmd->m_event_linkp = NULL;
133 return;
135 while (prev != NULL) {
136 if (prev->m_event_linkp == cmd) {
137 prev->m_event_linkp = cmd->m_event_linkp;
138 if (cmd->m_event_linkp == NULL) {
139 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
142 cmd->m_event_linkp = NULL;
143 return;
145 prev = prev->m_event_linkp;
149 static m_event_struct_t *
150 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
152 m_event_struct_t *ioc_cmd = NULL;
154 ioc_cmd = mpt->m_ioc_event_cmdq;
155 while (ioc_cmd != NULL) {
156 if (&(ioc_cmd->m_event_cmd) == cmd) {
157 return (ioc_cmd);
159 ioc_cmd = ioc_cmd->m_event_linkp;
161 ioc_cmd = NULL;
162 return (ioc_cmd);
165 void
166 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
168 m_event_struct_t *ioc_cmd = NULL;
169 m_event_struct_t *ioc_cmd_tmp = NULL;
170 ioc_cmd = mpt->m_ioc_event_cmdq;
173 * because the IOC event queue is resource of per instance for driver,
174 * it's not only ACK event commands used it, but also some others used
175 * it. We need destroy all ACK event commands when IOC reset, but can't
176 * disturb others.So we use filter to clear the ACK event cmd in ioc
177 * event queue, and other requests should be reserved, and they would
178 * be free by its owner.
180 while (ioc_cmd != NULL) {
181 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
182 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
183 if ((mpt->m_ioc_event_cmdq =
184 ioc_cmd->m_event_linkp) == NULL)
185 mpt->m_ioc_event_cmdtail =
186 &mpt->m_ioc_event_cmdq;
187 ioc_cmd_tmp = ioc_cmd;
188 ioc_cmd = ioc_cmd->m_event_linkp;
189 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
190 } else {
192 * it's not ack cmd, so continue to check next one
195 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
196 ioc_cmd = ioc_cmd->m_event_linkp;
202 void
203 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
205 pMpi2ConfigRequest_t request;
206 pMpi2SGESimple64_t sge;
207 struct scsi_pkt *pkt = cmd->cmd_pkt;
208 mptsas_config_request_t *config = pkt->pkt_ha_private;
209 uint8_t direction;
210 uint32_t length, flagslength, request_desc_low;
212 ASSERT(mutex_owned(&mpt->m_mutex));
215 * Point to the correct message and clear it as well as the global
216 * config page memory.
218 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
219 (mpt->m_req_frame_size * cmd->cmd_slot));
220 bzero(request, mpt->m_req_frame_size);
223 * Form the request message.
225 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
226 MPI2_FUNCTION_CONFIG);
227 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
228 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
229 length = 0;
230 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
231 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
232 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
233 ddi_put8(mpt->m_acc_req_frame_hdl,
234 &request->Header.PageType,
235 MPI2_CONFIG_PAGETYPE_EXTENDED);
236 ddi_put8(mpt->m_acc_req_frame_hdl,
237 &request->ExtPageType, config->page_type);
238 } else {
239 ddi_put8(mpt->m_acc_req_frame_hdl,
240 &request->Header.PageType, config->page_type);
242 } else {
243 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
244 config->ext_page_type);
245 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
246 config->ext_page_length);
247 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
248 config->page_type);
249 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
250 config->page_length);
251 ddi_put8(mpt->m_acc_req_frame_hdl,
252 &request->Header.PageVersion, config->page_version);
253 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
254 MPI2_CONFIG_PAGETYPE_EXTENDED) {
255 length = config->ext_page_length * 4;
256 } else {
257 length = config->page_length * 4;
260 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
261 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
263 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
264 (uint32_t)cmd->cmd_dma_addr);
265 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
266 (uint32_t)(cmd->cmd_dma_addr >> 32));
268 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
269 config->page_number);
270 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
271 config->page_address);
272 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
273 MPI2_SGE_FLAGS_END_OF_BUFFER |
274 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
275 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
276 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
277 direction |
278 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
279 flagslength |= length;
280 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
282 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
283 DDI_DMA_SYNC_FORDEV);
284 request_desc_low = (cmd->cmd_slot << 16) +
285 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
286 cmd->cmd_rfm = NULL;
287 MPTSAS_START_CMD(mpt, request_desc_low, 0);
288 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
289 DDI_SUCCESS) ||
290 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
291 DDI_SUCCESS)) {
292 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
297 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
298 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
299 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
301 va_list ap;
302 ddi_dma_attr_t attrs;
303 ddi_dma_cookie_t cookie;
304 ddi_acc_handle_t accessp;
305 size_t len = 0;
306 mptsas_config_request_t config;
307 int rval = DDI_SUCCESS, config_flags = 0;
308 mptsas_cmd_t *cmd;
309 struct scsi_pkt *pkt;
310 pMpi2ConfigReply_t reply;
311 uint16_t iocstatus = 0;
312 uint32_t iocloginfo;
313 caddr_t page_memp;
314 boolean_t free_dma = B_FALSE;
316 va_start(ap, callback);
317 ASSERT(mutex_owned(&mpt->m_mutex));
320 * Get a command from the pool.
322 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
323 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
324 "page request");
325 rval = DDI_FAILURE;
326 goto page_done;
328 config_flags |= MPTSAS_REQUEST_POOL_CMD;
330 bzero((caddr_t)cmd, sizeof (*cmd));
331 bzero((caddr_t)pkt, scsi_pkt_size());
332 bzero((caddr_t)&config, sizeof (config));
335 * Save the data for this request to be used in the call to start the
336 * config header request.
338 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
339 config.page_type = page_type;
340 config.page_number = page_number;
341 config.page_address = page_address;
344 * Form a blank cmd/pkt to store the acknowledgement message
346 pkt->pkt_ha_private = (opaque_t)&config;
347 pkt->pkt_flags = FLAG_HEAD;
348 pkt->pkt_time = 60;
349 cmd->cmd_pkt = pkt;
350 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
353 * Save the config header request message in a slot.
355 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
356 cmd->cmd_flags |= CFLAG_PREPARED;
357 mptsas_start_config_page_access(mpt, cmd);
358 } else {
359 mptsas_waitq_add(mpt, cmd);
363 * If this is a request for a RAID info page, or any page called during
364 * the RAID info page request, poll because these config page requests
365 * are nested. Poll to avoid data corruption due to one page's data
366 * overwriting the outer page request's data. This can happen when
367 * the mutex is released in cv_wait.
369 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
370 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
371 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
372 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
373 } else {
374 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
375 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
380 * Check if the header request completed without timing out
382 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
383 mptsas_log(mpt, CE_WARN, "config header request timeout");
384 rval = DDI_FAILURE;
385 goto page_done;
389 * cmd_rfm points to the reply message if a reply was given. Check the
390 * IOCStatus to make sure everything went OK with the header request.
392 if (cmd->cmd_rfm) {
393 config_flags |= MPTSAS_ADDRESS_REPLY;
394 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
395 DDI_DMA_SYNC_FORCPU);
396 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
397 - mpt->m_reply_frame_dma_addr));
398 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
399 &reply->Header.PageType);
400 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
401 &reply->Header.PageNumber);
402 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
403 &reply->Header.PageLength);
404 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
405 &reply->Header.PageVersion);
406 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
407 &reply->ExtPageType);
408 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
409 &reply->ExtPageLength);
411 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
412 &reply->IOCStatus);
413 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
414 &reply->IOCLogInfo);
416 if (iocstatus) {
417 NDBG13(("mptsas_access_config_page header: "
418 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
419 iocloginfo));
420 rval = DDI_FAILURE;
421 goto page_done;
424 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
425 MPI2_CONFIG_PAGETYPE_EXTENDED)
426 len = (config.ext_page_length * 4);
427 else
428 len = (config.page_length * 4);
432 if (pkt->pkt_reason == CMD_RESET) {
433 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
434 "request");
435 rval = DDI_FAILURE;
436 goto page_done;
440 * Put the reply frame back on the free queue, increment the free
441 * index, and write the new index to the free index register. But only
442 * if this reply is an ADDRESS reply.
444 if (config_flags & MPTSAS_ADDRESS_REPLY) {
445 ddi_put32(mpt->m_acc_free_queue_hdl,
446 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
447 cmd->cmd_rfm);
448 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
449 DDI_DMA_SYNC_FORDEV);
450 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
451 mpt->m_free_index = 0;
453 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
454 mpt->m_free_index);
455 config_flags &= (~MPTSAS_ADDRESS_REPLY);
459 * Allocate DMA buffer here. Store the info regarding this buffer in
460 * the cmd struct so that it can be used for this specific command and
461 * de-allocated after the command completes. The size of the reply
462 * will not be larger than the reply frame size.
464 attrs = mpt->m_msg_dma_attr;
465 attrs.dma_attr_sgllen = 1;
466 attrs.dma_attr_granular = (uint32_t)len;
468 if (mptsas_dma_addr_create(mpt, attrs,
469 &cmd->cmd_dmahandle, &accessp, &page_memp,
470 len, &cookie) == FALSE) {
471 rval = DDI_FAILURE;
472 mptsas_log(mpt, CE_WARN,
473 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
474 goto page_done;
476 /* NOW we can safely call mptsas_dma_addr_destroy(). */
477 free_dma = B_TRUE;
479 cmd->cmd_dma_addr = cookie.dmac_laddress;
480 bzero(page_memp, len);
483 * Save the data for this request to be used in the call to start the
484 * config page read
486 config.action = action;
487 config.page_address = page_address;
490 * Re-use the cmd that was used to get the header. Reset some of the
491 * values.
493 bzero((caddr_t)pkt, scsi_pkt_size());
494 pkt->pkt_ha_private = (opaque_t)&config;
495 pkt->pkt_flags = FLAG_HEAD;
496 pkt->pkt_time = 60;
497 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
500 * Send the config page request. cmd is re-used from header request.
502 mptsas_start_config_page_access(mpt, cmd);
505 * If this is a request for a RAID info page, or any page called during
506 * the RAID info page request, poll because these config page requests
507 * are nested. Poll to avoid data corruption due to one page's data
508 * overwriting the outer page request's data. This can happen when
509 * the mutex is released in cv_wait.
511 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
512 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
513 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
514 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
515 } else {
516 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
517 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
522 * Check if the request completed without timing out
524 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
525 mptsas_log(mpt, CE_WARN, "config page request timeout");
526 rval = DDI_FAILURE;
527 goto page_done;
531 * cmd_rfm points to the reply message if a reply was given. The reply
532 * frame and the config page are returned from this function in the
533 * param list.
535 if (cmd->cmd_rfm) {
536 config_flags |= MPTSAS_ADDRESS_REPLY;
537 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
538 DDI_DMA_SYNC_FORCPU);
539 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
540 DDI_DMA_SYNC_FORCPU);
541 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
542 - mpt->m_reply_frame_dma_addr));
543 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
544 &reply->IOCStatus);
545 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
546 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
547 &reply->IOCLogInfo);
550 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
551 rval = DDI_FAILURE;
552 goto page_done;
555 mptsas_fma_check(mpt, cmd);
557 * Check the DMA/ACC handles and then free the DMA buffer.
559 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
560 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
561 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
562 rval = DDI_FAILURE;
565 if (pkt->pkt_reason == CMD_TRAN_ERR) {
566 mptsas_log(mpt, CE_WARN, "config fma error");
567 rval = DDI_FAILURE;
568 goto page_done;
570 if (pkt->pkt_reason == CMD_RESET) {
571 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
572 rval = DDI_FAILURE;
573 goto page_done;
576 page_done:
577 va_end(ap);
579 * Put the reply frame back on the free queue, increment the free
580 * index, and write the new index to the free index register. But only
581 * if this reply is an ADDRESS reply.
583 if (config_flags & MPTSAS_ADDRESS_REPLY) {
584 ddi_put32(mpt->m_acc_free_queue_hdl,
585 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
586 cmd->cmd_rfm);
587 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
588 DDI_DMA_SYNC_FORDEV);
589 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
590 mpt->m_free_index = 0;
592 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
593 mpt->m_free_index);
596 if (free_dma)
597 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
599 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
600 mptsas_remove_cmd(mpt, cmd);
601 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
603 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
604 mptsas_return_to_pool(mpt, cmd);
606 if (config_flags & MPTSAS_CMD_TIMEOUT) {
607 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
608 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
609 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
613 return (rval);
617 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
618 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
619 uint8_t pagelength, uint32_t SGEflagslength, uint32_t SGEaddress32)
621 pMpi2ConfigRequest_t config;
622 int send_numbytes;
624 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
625 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
626 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
627 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
628 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
629 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
630 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
631 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
632 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
633 ddi_put32(mpt->m_hshk_acc_hdl,
634 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
635 ddi_put32(mpt->m_hshk_acc_hdl,
636 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
637 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
640 * Post message via handshake
642 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
643 mpt->m_hshk_acc_hdl)) {
644 return (-1);
646 return (0);
650 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
651 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
652 uint8_t pageversion, uint16_t extpagelength,
653 uint32_t SGEflagslength, uint32_t SGEaddress32)
655 pMpi2ConfigRequest_t config;
656 int send_numbytes;
658 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
659 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
660 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
661 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
662 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
663 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
664 MPI2_CONFIG_PAGETYPE_EXTENDED);
665 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
666 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
667 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
668 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
669 ddi_put32(mpt->m_hshk_acc_hdl,
670 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
671 ddi_put32(mpt->m_hshk_acc_hdl,
672 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
673 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
676 * Post message via handshake
678 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
679 mpt->m_hshk_acc_hdl)) {
680 return (-1);
682 return (0);
686 mptsas_ioc_wait_for_response(mptsas_t *mpt)
688 int polls = 0;
690 while ((ddi_get32(mpt->m_datap,
691 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
692 drv_usecwait(1000);
693 if (polls++ > 60000) {
694 return (-1);
697 return (0);
701 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
703 int polls = 0;
705 while ((ddi_get32(mpt->m_datap,
706 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
707 drv_usecwait(1000);
708 if (polls++ > 300000) {
709 return (-1);
712 return (0);
716 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
717 ddi_acc_handle_t accessp)
719 int i;
722 * clean pending doorbells
724 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
725 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
726 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
727 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
729 if (mptsas_ioc_wait_for_doorbell(mpt)) {
730 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
731 return (-1);
735 * clean pending doorbells again
737 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
739 if (mptsas_ioc_wait_for_response(mpt)) {
740 NDBG19(("mptsas_send_handshake failed. Doorbell not "
741 "cleared\n"));
742 return (-1);
746 * post handshake message
748 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
749 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
750 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
751 if (mptsas_ioc_wait_for_response(mpt)) {
752 NDBG19(("mptsas_send_handshake failed posting "
753 "message\n"));
754 return (-1);
758 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
759 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
760 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
761 return (-1);
764 return (0);
768 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
769 ddi_acc_handle_t accessp)
771 int i, totalbytes, bytesleft;
772 uint16_t val;
775 * wait for doorbell
777 if (mptsas_ioc_wait_for_doorbell(mpt)) {
778 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
779 return (-1);
783 * get first 2 bytes of handshake message to determine how much
784 * data we will be getting
786 for (i = 0; i < 2; i++, memp += 2) {
787 val = (ddi_get32(mpt->m_datap,
788 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
789 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
790 if (mptsas_ioc_wait_for_doorbell(mpt)) {
791 NDBG19(("mptsas_get_handshake failure getting initial"
792 " data\n"));
793 return (-1);
795 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
796 if (i == 1) {
797 totalbytes = (val & 0xFF) * 2;
802 * If we are expecting less bytes than the message wants to send
803 * we simply save as much as we expected and then throw out the rest
804 * later
806 if (totalbytes > (numbytes / 2)) {
807 bytesleft = ((numbytes / 2) - 2);
808 } else {
809 bytesleft = (totalbytes - 2);
813 * Get the rest of the data
815 for (i = 0; i < bytesleft; i++, memp += 2) {
816 val = (ddi_get32(mpt->m_datap,
817 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
818 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
819 if (mptsas_ioc_wait_for_doorbell(mpt)) {
820 NDBG19(("mptsas_get_handshake failure getting"
821 " main data\n"));
822 return (-1);
824 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
828 * Sometimes the device will send more data than is expected
829 * This data is not used by us but needs to be cleared from
830 * ioc doorbell. So we just read the values and throw
831 * them out.
833 if (totalbytes > (numbytes / 2)) {
834 for (i = (numbytes / 2); i < totalbytes; i++) {
835 val = (ddi_get32(mpt->m_datap,
836 &mpt->m_reg->Doorbell) &
837 MPI2_DOORBELL_DATA_MASK);
838 ddi_put32(mpt->m_datap,
839 &mpt->m_reg->HostInterruptStatus, 0);
840 if (mptsas_ioc_wait_for_doorbell(mpt)) {
841 NDBG19(("mptsas_get_handshake failure getting "
842 "extra garbage data\n"));
843 return (-1);
848 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
850 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
851 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
852 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
853 return (-1);
856 return (0);
860 mptsas_kick_start(mptsas_t *mpt)
862 int polls = 0;
863 uint32_t diag_reg, ioc_state, saved_HCB_size;
866 * Start a hard reset. Write magic number and wait 500 mSeconds.
868 MPTSAS_ENABLE_DRWE(mpt);
869 drv_usecwait(500000);
872 * Read the current Diag Reg and save the Host Controlled Boot size.
874 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
875 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
878 * Set Reset Adapter bit and wait 50 mSeconds.
880 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
881 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
882 drv_usecwait(50000);
885 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
886 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
887 * If no more adapter (all FF's), just return failure.
889 for (polls = 0; polls < 600000; polls++) {
890 diag_reg = ddi_get32(mpt->m_datap,
891 &mpt->m_reg->HostDiagnostic);
892 if (diag_reg == 0xFFFFFFFF) {
893 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
894 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
895 return (DDI_FAILURE);
897 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
898 break;
900 drv_usecwait(500);
902 if (polls == 600000) {
903 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
904 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
905 return (DDI_FAILURE);
909 * Check if adapter is in Host Boot Mode. If so, restart adapter
910 * assuming the HCB points to good FW.
911 * Set BootDeviceSel to HCDW (Host Code and Data Window).
913 if (diag_reg & MPI2_DIAG_HCB_MODE) {
914 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
915 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
916 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
919 * Re-enable the HCDW.
921 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
922 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
926 * Restart the adapter.
928 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
929 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
932 * Disable writes to the Host Diag register.
934 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
935 MPI2_WRSEQ_FLUSH_KEY_VALUE);
938 * Wait 60 seconds max for FW to come to ready state.
940 for (polls = 0; polls < 60000; polls++) {
941 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
942 if (ioc_state == 0xFFFFFFFF) {
943 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
944 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
945 return (DDI_FAILURE);
947 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
948 MPI2_IOC_STATE_READY) {
949 break;
951 drv_usecwait(1000);
953 if (polls == 60000) {
954 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
955 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
956 return (DDI_FAILURE);
960 * Clear the ioc ack events queue.
962 mptsas_destroy_ioc_event_cmd(mpt);
964 return (DDI_SUCCESS);
968 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
970 int polls = 0;
971 uint32_t reset_msg;
972 uint32_t ioc_state;
974 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
976 * If chip is already in ready state then there is nothing to do.
978 if (ioc_state == MPI2_IOC_STATE_READY) {
979 return (MPTSAS_NO_RESET);
982 * If the chip is already operational, we just need to send
983 * it a message unit reset to put it back in the ready state
985 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
987 * If the first time, try MUR anyway, because we haven't even
988 * queried the card for m_event_replay and other capabilities.
989 * Other platforms do it this way, we can still do a hard
990 * reset if we need to, MUR takes less time than a full
991 * adapter reset, and there are reports that some HW
992 * combinations will lock up when receiving a hard reset.
994 if ((first_time || mpt->m_event_replay) &&
995 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
996 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
997 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
998 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
999 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1000 if (mptsas_ioc_wait_for_response(mpt)) {
1001 NDBG19(("mptsas_ioc_reset failure sending "
1002 "message_unit_reset\n"));
1003 goto hard_reset;
1007 * Wait no more than 60 seconds for chip to become
1008 * ready.
1010 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1011 MPI2_IOC_STATE_READY) == 0x0) {
1012 drv_usecwait(1000);
1013 if (polls++ > 60000) {
1014 goto hard_reset;
1019 * Save the last reset mode done on IOC which will be
1020 * helpful while resuming from suspension.
1022 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1025 * the message unit reset would do reset operations
1026 * clear reply and request queue, so we should clear
1027 * ACK event cmd.
1029 mptsas_destroy_ioc_event_cmd(mpt);
1030 return (MPTSAS_SUCCESS_MUR);
1033 hard_reset:
1034 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1035 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1036 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1037 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1038 return (MPTSAS_RESET_FAIL);
1040 return (MPTSAS_SUCCESS_HARDRESET);
1045 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1046 struct scsi_pkt **pkt)
1048 m_event_struct_t *ioc_cmd = NULL;
1050 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1051 if (ioc_cmd == NULL) {
1052 return (DDI_FAILURE);
1054 ioc_cmd->m_event_linkp = NULL;
1055 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1056 *cmd = &(ioc_cmd->m_event_cmd);
1057 *pkt = &(ioc_cmd->m_event_pkt);
1059 return (DDI_SUCCESS);
1062 void
1063 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1065 m_event_struct_t *ioc_cmd = NULL;
1067 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1068 if (ioc_cmd == NULL) {
1069 return;
1072 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1073 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1074 ioc_cmd = NULL;
1078 * NOTE: We should be able to queue TM requests in the controller to make this
1079 * a lot faster. If resetting all targets, for example, we can load the hi
1080 * priority queue with its limit and the controller will reply as they are
1081 * completed. This way, we don't have to poll for one reply at a time.
1082 * Think about enhancing this later.
1085 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1086 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1089 * In order to avoid allocating variables on the stack,
1090 * we make use of the pre-existing mptsas_cmd_t and
1091 * scsi_pkt which are included in the mptsas_t which
1092 * is passed to this routine.
1095 pMpi2SCSITaskManagementRequest_t task;
1096 int rval = FALSE;
1097 mptsas_cmd_t *cmd;
1098 struct scsi_pkt *pkt;
1099 mptsas_slots_t *slots = mpt->m_active;
1100 uint32_t request_desc_low, i;
1101 pMPI2DefaultReply_t reply_msg;
1104 * Can't start another task management routine.
1106 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1107 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1108 " command at a time\n");
1109 return (FALSE);
1112 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1113 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1115 bzero((caddr_t)cmd, sizeof (*cmd));
1116 bzero((caddr_t)pkt, scsi_pkt_size());
1118 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1119 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1120 pkt->pkt_ha_private = (opaque_t)cmd;
1121 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1122 pkt->pkt_time = 60;
1123 pkt->pkt_address.a_target = dev_handle;
1124 pkt->pkt_address.a_lun = (uchar_t)lun;
1125 cmd->cmd_pkt = pkt;
1126 cmd->cmd_scblen = 1;
1127 cmd->cmd_flags = CFLAG_TM_CMD;
1128 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1130 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1133 * Store the TM message in memory location corresponding to the TM slot
1134 * number.
1136 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1137 (mpt->m_req_frame_size * cmd->cmd_slot));
1138 bzero(task, mpt->m_req_frame_size);
1141 * form message for requested task
1143 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1144 MPI2_FUNCTION_SCSI_TASK_MGMT);
1147 * Set the task type
1149 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1152 * Send TM request using High Priority Queue.
1154 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1155 DDI_DMA_SYNC_FORDEV);
1156 request_desc_low = (cmd->cmd_slot << 16) +
1157 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1158 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1159 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1161 if (pkt->pkt_reason == CMD_INCOMPLETE)
1162 rval = FALSE;
1165 * If a reply frame was used and there is a reply buffer to copy the
1166 * reply data into, copy it. If this fails, log a message, but don't
1167 * fail the TM request.
1169 if (cmd->cmd_rfm && reply) {
1170 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1171 DDI_DMA_SYNC_FORCPU);
1172 reply_msg = (pMPI2DefaultReply_t)
1173 (mpt->m_reply_frame + (cmd->cmd_rfm -
1174 mpt->m_reply_frame_dma_addr));
1175 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1176 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1178 mutex_exit(&mpt->m_mutex);
1179 for (i = 0; i < reply_size; i++) {
1180 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1181 mode)) {
1182 mptsas_log(mpt, CE_WARN, "failed to copy out "
1183 "reply data for TM request");
1184 break;
1187 mutex_enter(&mpt->m_mutex);
1191 * clear the TM slot before returning
1193 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1196 * If we lost our task management command
1197 * we need to reset the ioc
1199 if (rval == FALSE) {
1200 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1201 "try to reset ioc to recovery!");
1202 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1203 if (mptsas_restart_ioc(mpt)) {
1204 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1205 rval = FAILED;
1209 return (rval);
1213 * Complete firmware download frame for v2.0 cards.
1215 static void
1216 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1217 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1218 ddi_dma_cookie_t flsh_cookie)
1220 pMpi2FWDownloadTCSGE_t tcsge;
1221 pMpi2SGESimple64_t sge;
1222 uint32_t flagslength;
1224 ddi_put8(acc_hdl, &fwdownload->Function,
1225 MPI2_FUNCTION_FW_DOWNLOAD);
1226 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1227 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1228 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1229 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1231 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1232 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1233 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1234 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1235 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1236 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1238 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1239 flagslength = size;
1240 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1241 MPI2_SGE_FLAGS_END_OF_BUFFER |
1242 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1243 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1244 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1245 MPI2_SGE_FLAGS_HOST_TO_IOC |
1246 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1247 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1248 ddi_put32(acc_hdl, &sge->Address.Low,
1249 flsh_cookie.dmac_address);
1250 ddi_put32(acc_hdl, &sge->Address.High,
1251 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1255 * Complete firmware download frame for v2.5 cards.
1257 static void
1258 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1259 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1260 ddi_dma_cookie_t flsh_cookie)
1262 pMpi2IeeeSgeSimple64_t sge;
1263 uint8_t flags;
1265 ddi_put8(acc_hdl, &fwdownload->Function,
1266 MPI2_FUNCTION_FW_DOWNLOAD);
1267 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1268 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1269 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1270 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1272 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1273 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1275 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1276 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1277 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1278 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1279 ddi_put8(acc_hdl, &sge->Flags, flags);
1280 ddi_put32(acc_hdl, &sge->Length, size);
1281 ddi_put32(acc_hdl, &sge->Address.Low,
1282 flsh_cookie.dmac_address);
1283 ddi_put32(acc_hdl, &sge->Address.High,
1284 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1287 static int mptsas_enable_mpi25_flashupdate = 0;
1290 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1291 uint8_t type, int mode)
1295 * In order to avoid allocating variables on the stack,
1296 * we make use of the pre-existing mptsas_cmd_t and
1297 * scsi_pkt which are included in the mptsas_t which
1298 * is passed to this routine.
1301 ddi_dma_attr_t flsh_dma_attrs;
1302 ddi_dma_cookie_t flsh_cookie;
1303 ddi_dma_handle_t flsh_dma_handle;
1304 ddi_acc_handle_t flsh_accessp;
1305 caddr_t memp, flsh_memp;
1306 mptsas_cmd_t *cmd;
1307 struct scsi_pkt *pkt;
1308 int i;
1309 int rvalue = 0;
1310 uint32_t request_desc_low;
1312 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1314 * The code is there but not tested yet.
1315 * User has to know there are risks here.
1317 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1318 "Updating firmware through MPI 2.5 has not been "
1319 "tested yet!\n"
1320 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1321 return (-1);
1322 } /* Otherwise, you pay your money and you take your chances. */
1324 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1325 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1326 "failed. event ack command pool is full\n");
1327 return (rvalue);
1330 bzero((caddr_t)cmd, sizeof (*cmd));
1331 bzero((caddr_t)pkt, scsi_pkt_size());
1332 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1335 * dynamically create a customized dma attribute structure
1336 * that describes the flash file.
1338 flsh_dma_attrs = mpt->m_msg_dma_attr;
1339 flsh_dma_attrs.dma_attr_sgllen = 1;
1341 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1342 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1343 mptsas_log(mpt, CE_WARN,
1344 "(unable to allocate dma resource.");
1345 mptsas_return_to_pool(mpt, cmd);
1346 return (-1);
1349 bzero(flsh_memp, size);
1351 for (i = 0; i < size; i++) {
1352 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1354 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1357 * form a cmd/pkt to store the fw download message
1359 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1360 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1361 pkt->pkt_ha_private = (opaque_t)cmd;
1362 pkt->pkt_flags = FLAG_HEAD;
1363 pkt->pkt_time = 60;
1364 cmd->cmd_pkt = pkt;
1365 cmd->cmd_scblen = 1;
1366 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1369 * Save the command in a slot
1371 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1372 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1373 mptsas_return_to_pool(mpt, cmd);
1374 return (-1);
1378 * Fill in fw download message
1380 ASSERT(cmd->cmd_slot != 0);
1381 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1382 bzero(memp, mpt->m_req_frame_size);
1384 if (mpt->m_MPI25)
1385 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1386 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1387 else
1388 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1389 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1392 * Start command
1394 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1395 DDI_DMA_SYNC_FORDEV);
1396 request_desc_low = (cmd->cmd_slot << 16) +
1397 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1398 cmd->cmd_rfm = NULL;
1399 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1401 rvalue = 0;
1402 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1403 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1404 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1405 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1406 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1407 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1409 rvalue = -1;
1411 mptsas_remove_cmd(mpt, cmd);
1412 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1414 return (rvalue);
1417 static int
1418 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1419 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1420 va_list ap)
1422 #ifndef __lock_lint
1423 _NOTE(ARGUNUSED(ap))
1424 #endif
1425 pMpi2SasDevicePage0_t sasdevpage;
1426 int rval = DDI_SUCCESS, i;
1427 uint8_t *sas_addr = NULL;
1428 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1429 uint16_t *devhdl, *bay_num, *enclosure;
1430 uint64_t *sas_wwn;
1431 uint32_t *dev_info;
1432 uint8_t *physport, *phynum;
1433 uint16_t *pdevhdl, *io_flags;
1434 uint32_t page_address;
1436 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1437 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1438 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1439 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1440 iocstatus, iocloginfo);
1441 rval = DDI_FAILURE;
1442 return (rval);
1444 page_address = va_arg(ap, uint32_t);
1446 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1447 * are no more pages. If everything is OK up to this point but the
1448 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1449 * signal that device traversal is complete.
1451 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1452 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1453 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1454 mpt->m_done_traverse_dev = 1;
1456 rval = DDI_FAILURE;
1457 return (rval);
1459 devhdl = va_arg(ap, uint16_t *);
1460 sas_wwn = va_arg(ap, uint64_t *);
1461 dev_info = va_arg(ap, uint32_t *);
1462 physport = va_arg(ap, uint8_t *);
1463 phynum = va_arg(ap, uint8_t *);
1464 pdevhdl = va_arg(ap, uint16_t *);
1465 bay_num = va_arg(ap, uint16_t *);
1466 enclosure = va_arg(ap, uint16_t *);
1467 io_flags = va_arg(ap, uint16_t *);
1469 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1471 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1472 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1473 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1474 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1475 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1477 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1478 *sas_wwn = LE_64(*sas_wwn);
1479 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1480 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1481 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1482 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1483 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1484 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1486 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1488 * Leave a messages about FP cabability in the log.
1490 mptsas_log(mpt, CE_CONT,
1491 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1492 (*io_flags &
1493 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1494 " and Enabled":" but Disabled");
1497 return (rval);
1501 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1502 * info and SAS address.
1505 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1506 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1507 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1508 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1510 int rval = DDI_SUCCESS;
1512 ASSERT(mutex_owned(&mpt->m_mutex));
1515 * Get the header and config page. reply contains the reply frame,
1516 * which holds status info for the request.
1518 rval = mptsas_access_config_page(mpt,
1519 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1520 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1521 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1522 dev_info, physport, phynum, pdev_handle,
1523 bay_num, enclosure, io_flags);
1525 return (rval);
1528 static int
1529 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1530 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1531 va_list ap)
1533 #ifndef __lock_lint
1534 _NOTE(ARGUNUSED(ap))
1535 #endif
1536 pMpi2ExpanderPage0_t expddevpage;
1537 int rval = DDI_SUCCESS, i;
1538 uint8_t *sas_addr = NULL;
1539 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1540 uint16_t *devhdl;
1541 uint64_t *sas_wwn;
1542 uint8_t physport;
1543 mptsas_phymask_t *phymask;
1544 uint16_t *pdevhdl;
1545 uint32_t page_address;
1547 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1548 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1549 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1550 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1551 iocstatus, iocloginfo);
1552 rval = DDI_FAILURE;
1553 return (rval);
1555 page_address = va_arg(ap, uint32_t);
1557 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1558 * are no more pages. If everything is OK up to this point but the
1559 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1560 * signal that device traversal is complete.
1562 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1563 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1564 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1565 mpt->m_done_traverse_smp = 1;
1567 rval = DDI_FAILURE;
1568 return (rval);
1570 devhdl = va_arg(ap, uint16_t *);
1571 sas_wwn = va_arg(ap, uint64_t *);
1572 phymask = va_arg(ap, mptsas_phymask_t *);
1573 pdevhdl = va_arg(ap, uint16_t *);
1575 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1577 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1578 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1579 *phymask = mptsas_physport_to_phymask(mpt, physport);
1580 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1581 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1582 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1583 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1585 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1586 *sas_wwn = LE_64(*sas_wwn);
1588 return (rval);
1592 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1593 * and SAS address.
1596 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1597 mptsas_smp_t *info)
1599 int rval = DDI_SUCCESS;
1601 ASSERT(mutex_owned(&mpt->m_mutex));
1604 * Get the header and config page. reply contains the reply frame,
1605 * which holds status info for the request.
1607 rval = mptsas_access_config_page(mpt,
1608 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1609 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1610 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1611 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1613 return (rval);
1616 static int
1617 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1618 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1619 va_list ap)
1621 #ifndef __lock_lint
1622 _NOTE(ARGUNUSED(ap))
1623 #endif
1624 int rval = DDI_SUCCESS, i;
1625 uint8_t *sas_addr = NULL;
1626 uint64_t *sas_wwn;
1627 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1628 uint8_t *portwidth;
1629 pMpi2SasPortPage0_t sasportpage;
1631 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1632 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1633 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1634 iocstatus, iocloginfo);
1635 rval = DDI_FAILURE;
1636 return (rval);
1638 sas_wwn = va_arg(ap, uint64_t *);
1639 portwidth = va_arg(ap, uint8_t *);
1641 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1642 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1643 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1644 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1646 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1647 *sas_wwn = LE_64(*sas_wwn);
1648 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1649 return (rval);
1653 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1654 * and port width.
1657 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1658 uint64_t *sas_wwn, uint8_t *portwidth)
1660 int rval = DDI_SUCCESS;
1662 ASSERT(mutex_owned(&mpt->m_mutex));
1665 * Get the header and config page. reply contains the reply frame,
1666 * which holds status info for the request.
1668 rval = mptsas_access_config_page(mpt,
1669 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1670 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1671 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1673 return (rval);
1676 static int
1677 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1678 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1679 va_list ap)
1681 #ifndef __lock_lint
1682 _NOTE(ARGUNUSED(ap))
1683 #endif
1684 int rval = DDI_SUCCESS;
1685 pMpi2SasIOUnitPage0_t sasioupage0;
1686 int i, num_phys;
1687 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1688 uint8_t port_flags;
1690 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1691 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1692 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1693 iocstatus, iocloginfo);
1694 rval = DDI_FAILURE;
1695 return (rval);
1697 readpage1 = va_arg(ap, uint32_t *);
1698 retrypage0 = va_arg(ap, uint32_t *);
1700 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1702 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1704 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1705 * was initially set. This should never change throughout the life of
1706 * the driver.
1708 ASSERT(num_phys == mpt->m_num_phys);
1709 for (i = 0; i < num_phys; i++) {
1710 cpdi[i] = ddi_get32(accessp,
1711 &sasioupage0->PhyData[i].
1712 ControllerPhyDeviceInfo);
1713 port_flags = ddi_get8(accessp,
1714 &sasioupage0->PhyData[i].PortFlags);
1715 mpt->m_phy_info[i].port_num =
1716 ddi_get8(accessp,
1717 &sasioupage0->PhyData[i].Port);
1718 mpt->m_phy_info[i].ctrl_devhdl =
1719 ddi_get16(accessp, &sasioupage0->
1720 PhyData[i].ControllerDevHandle);
1721 mpt->m_phy_info[i].attached_devhdl =
1722 ddi_get16(accessp, &sasioupage0->
1723 PhyData[i].AttachedDevHandle);
1724 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1725 mpt->m_phy_info[i].port_flags = port_flags;
1727 if (port_flags & DISCOVERY_IN_PROGRESS) {
1728 *retrypage0 = *retrypage0 + 1;
1729 break;
1730 } else {
1731 *retrypage0 = 0;
1733 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1735 * some PHY configuration described in
1736 * SAS IO Unit Page1
1738 *readpage1 = 1;
1742 return (rval);
1745 static int
1746 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1747 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1748 va_list ap)
1750 #ifndef __lock_lint
1751 _NOTE(ARGUNUSED(ap))
1752 #endif
1753 int rval = DDI_SUCCESS;
1754 pMpi2SasIOUnitPage1_t sasioupage1;
1755 int i, num_phys;
1756 uint32_t cpdi[MPTSAS_MAX_PHYS];
1757 uint8_t port_flags;
1759 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1760 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1761 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1762 iocstatus, iocloginfo);
1763 rval = DDI_FAILURE;
1764 return (rval);
1767 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1768 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1770 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1771 * was initially set. This should never change throughout the life of
1772 * the driver.
1774 ASSERT(num_phys == mpt->m_num_phys);
1775 for (i = 0; i < num_phys; i++) {
1776 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1777 ControllerPhyDeviceInfo);
1778 port_flags = ddi_get8(accessp,
1779 &sasioupage1->PhyData[i].PortFlags);
1780 mpt->m_phy_info[i].port_num =
1781 ddi_get8(accessp,
1782 &sasioupage1->PhyData[i].Port);
1783 mpt->m_phy_info[i].port_flags = port_flags;
1784 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1786 return (rval);
1790 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1791 * page1 to update the PHY information. This is the message passing method of
1792 * this function which should be called except during initialization.
1795 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1797 int rval = DDI_SUCCESS, state;
1798 uint32_t readpage1 = 0, retrypage0 = 0;
1800 ASSERT(mutex_owned(&mpt->m_mutex));
1803 * Now we cycle through the state machine. Here's what happens:
1804 * 1. Read IO unit page 0 and set phy information
1805 * 2. See if Read IO unit page1 is needed because of port configuration
1806 * 3. Read IO unit page 1 and update phy information.
1808 state = IOUC_READ_PAGE0;
1809 while (state != IOUC_DONE) {
1810 if (state == IOUC_READ_PAGE0) {
1811 rval = mptsas_access_config_page(mpt,
1812 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1813 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1814 mptsas_sasiou_page_0_cb, &readpage1,
1815 &retrypage0);
1816 } else if (state == IOUC_READ_PAGE1) {
1817 rval = mptsas_access_config_page(mpt,
1818 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1819 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1820 mptsas_sasiou_page_1_cb);
1823 if (rval == DDI_SUCCESS) {
1824 switch (state) {
1825 case IOUC_READ_PAGE0:
1827 * retry 30 times if discovery is in process
1829 if (retrypage0 && (retrypage0 < 30)) {
1830 drv_usecwait(1000 * 100);
1831 state = IOUC_READ_PAGE0;
1832 break;
1833 } else if (retrypage0 == 30) {
1834 mptsas_log(mpt, CE_WARN,
1835 "!Discovery in progress, can't "
1836 "verify IO unit config, then "
1837 "after 30 times retry, give "
1838 "up!");
1839 state = IOUC_DONE;
1840 rval = DDI_FAILURE;
1841 break;
1844 if (readpage1 == 0) {
1845 state = IOUC_DONE;
1846 rval = DDI_SUCCESS;
1847 break;
1850 state = IOUC_READ_PAGE1;
1851 break;
1853 case IOUC_READ_PAGE1:
1854 state = IOUC_DONE;
1855 rval = DDI_SUCCESS;
1856 break;
1858 } else {
1859 return (rval);
1863 return (rval);
1866 static int
1867 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1868 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1869 va_list ap)
1871 #ifndef __lock_lint
1872 _NOTE(ARGUNUSED(ap))
1873 #endif
1874 pMpi2BiosPage3_t sasbiospage;
1875 int rval = DDI_SUCCESS;
1876 uint32_t *bios_version;
1878 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1879 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1880 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1881 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1882 rval = DDI_FAILURE;
1883 return (rval);
1885 bios_version = va_arg(ap, uint32_t *);
1886 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1887 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1889 return (rval);
1893 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1894 * other information in this page is not needed, just ignore it.
1897 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1899 int rval = DDI_SUCCESS;
1901 ASSERT(mutex_owned(&mpt->m_mutex));
1904 * Get the header and config page. reply contains the reply frame,
1905 * which holds status info for the request.
1907 rval = mptsas_access_config_page(mpt,
1908 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1909 0, mptsas_biospage_3_cb, bios_version);
1911 return (rval);
1915 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1916 * page1 to update the PHY information. This is the handshaking version of
1917 * this function, which should be called during initialization only.
1920 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1922 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1923 ddi_dma_cookie_t page_cookie;
1924 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1925 ddi_acc_handle_t recv_accessp, page_accessp;
1926 pMpi2ConfigReply_t configreply;
1927 pMpi2SasIOUnitPage0_t sasioupage0;
1928 pMpi2SasIOUnitPage1_t sasioupage1;
1929 int recv_numbytes;
1930 caddr_t recv_memp, page_memp;
1931 int i, num_phys, start_phy = 0;
1932 int page0_size =
1933 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1934 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1935 int page1_size =
1936 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1937 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1938 uint32_t flags_length;
1939 uint32_t cpdi[MPTSAS_MAX_PHYS];
1940 uint32_t readpage1 = 0, retrypage0 = 0;
1941 uint16_t iocstatus;
1942 uint8_t port_flags, page_number, action;
1943 uint32_t reply_size = 256; /* Big enough for any page */
1944 uint_t state;
1945 int rval = DDI_FAILURE;
1946 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1949 * Initialize our "state machine". This is a bit convoluted,
1950 * but it keeps us from having to do the ddi allocations numerous
1951 * times.
1954 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1955 ASSERT(mutex_owned(&mpt->m_mutex));
1956 state = IOUC_READ_PAGE0;
1959 * dynamically create a customized dma attribute structure
1960 * that describes mpt's config reply page request structure.
1962 recv_dma_attrs = mpt->m_msg_dma_attr;
1963 recv_dma_attrs.dma_attr_sgllen = 1;
1964 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1966 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1967 &recv_dma_handle, &recv_accessp, &recv_memp,
1968 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1969 mptsas_log(mpt, CE_WARN,
1970 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1971 goto cleanup;
1973 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1974 free_recv = B_TRUE;
1976 page_dma_attrs = mpt->m_msg_dma_attr;
1977 page_dma_attrs.dma_attr_sgllen = 1;
1978 page_dma_attrs.dma_attr_granular = reply_size;
1980 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1981 &page_dma_handle, &page_accessp, &page_memp,
1982 reply_size, &page_cookie) == FALSE) {
1983 mptsas_log(mpt, CE_WARN,
1984 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1985 goto cleanup;
1987 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1988 free_page = B_TRUE;
1991 * Now we cycle through the state machine. Here's what happens:
1992 * 1. Read IO unit page 0 and set phy information
1993 * 2. See if Read IO unit page1 is needed because of port configuration
1994 * 3. Read IO unit page 1 and update phy information.
1997 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1998 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
2000 while (state != IOUC_DONE) {
2001 switch (state) {
2002 case IOUC_READ_PAGE0:
2003 page_number = 0;
2004 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2005 flags_length = (uint32_t)page0_size;
2006 flags_length |= ((uint32_t)(
2007 MPI2_SGE_FLAGS_LAST_ELEMENT |
2008 MPI2_SGE_FLAGS_END_OF_BUFFER |
2009 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2010 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2011 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2012 MPI2_SGE_FLAGS_IOC_TO_HOST |
2013 MPI2_SGE_FLAGS_END_OF_LIST) <<
2014 MPI2_SGE_FLAGS_SHIFT);
2016 break;
2018 case IOUC_READ_PAGE1:
2019 page_number = 1;
2020 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2021 flags_length = (uint32_t)page1_size;
2022 flags_length |= ((uint32_t)(
2023 MPI2_SGE_FLAGS_LAST_ELEMENT |
2024 MPI2_SGE_FLAGS_END_OF_BUFFER |
2025 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2026 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2027 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2028 MPI2_SGE_FLAGS_IOC_TO_HOST |
2029 MPI2_SGE_FLAGS_END_OF_LIST) <<
2030 MPI2_SGE_FLAGS_SHIFT);
2032 break;
2033 default:
2034 break;
2037 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2038 configreply = (pMpi2ConfigReply_t)recv_memp;
2039 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2041 if (mptsas_send_extended_config_request_msg(mpt,
2042 MPI2_CONFIG_ACTION_PAGE_HEADER,
2043 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2044 0, page_number, 0, 0, 0, 0)) {
2045 goto cleanup;
2048 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2049 recv_accessp)) {
2050 goto cleanup;
2053 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2054 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2056 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2057 mptsas_log(mpt, CE_WARN,
2058 "mptsas_get_sas_io_unit_page_hndshk: read page "
2059 "header iocstatus = 0x%x", iocstatus);
2060 goto cleanup;
2063 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2064 bzero(page_memp, reply_size);
2067 if (mptsas_send_extended_config_request_msg(mpt, action,
2068 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2069 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2070 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2071 flags_length, page_cookie.dmac_address)) {
2072 goto cleanup;
2075 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2076 recv_accessp)) {
2077 goto cleanup;
2080 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2081 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2083 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2084 mptsas_log(mpt, CE_WARN,
2085 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2086 "config failed for action %d, iocstatus = 0x%x",
2087 action, iocstatus);
2088 goto cleanup;
2091 switch (state) {
2092 case IOUC_READ_PAGE0:
2093 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2094 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2095 goto cleanup;
2098 num_phys = ddi_get8(page_accessp,
2099 &sasioupage0->NumPhys);
2100 ASSERT(num_phys == mpt->m_num_phys);
2101 if (num_phys > MPTSAS_MAX_PHYS) {
2102 mptsas_log(mpt, CE_WARN, "Number of phys "
2103 "supported by HBA (%d) is more than max "
2104 "supported by driver (%d). Driver will "
2105 "not attach.", num_phys,
2106 MPTSAS_MAX_PHYS);
2107 rval = DDI_FAILURE;
2108 goto cleanup;
2110 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2111 cpdi[i] = ddi_get32(page_accessp,
2112 &sasioupage0->PhyData[i].
2113 ControllerPhyDeviceInfo);
2114 port_flags = ddi_get8(page_accessp,
2115 &sasioupage0->PhyData[i].PortFlags);
2117 mpt->m_phy_info[i].port_num =
2118 ddi_get8(page_accessp,
2119 &sasioupage0->PhyData[i].Port);
2120 mpt->m_phy_info[i].ctrl_devhdl =
2121 ddi_get16(page_accessp, &sasioupage0->
2122 PhyData[i].ControllerDevHandle);
2123 mpt->m_phy_info[i].attached_devhdl =
2124 ddi_get16(page_accessp, &sasioupage0->
2125 PhyData[i].AttachedDevHandle);
2126 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2127 mpt->m_phy_info[i].port_flags = port_flags;
2129 if (port_flags & DISCOVERY_IN_PROGRESS) {
2130 retrypage0++;
2131 NDBG20(("Discovery in progress, can't "
2132 "verify IO unit config, then NO.%d"
2133 " times retry", retrypage0));
2134 break;
2135 } else {
2136 retrypage0 = 0;
2138 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2140 * some PHY configuration described in
2141 * SAS IO Unit Page1
2143 readpage1 = 1;
2148 * retry 30 times if discovery is in process
2150 if (retrypage0 && (retrypage0 < 30)) {
2151 drv_usecwait(1000 * 100);
2152 state = IOUC_READ_PAGE0;
2153 break;
2154 } else if (retrypage0 == 30) {
2155 mptsas_log(mpt, CE_WARN,
2156 "!Discovery in progress, can't "
2157 "verify IO unit config, then after"
2158 " 30 times retry, give up!");
2159 state = IOUC_DONE;
2160 rval = DDI_FAILURE;
2161 break;
2164 if (readpage1 == 0) {
2165 state = IOUC_DONE;
2166 rval = DDI_SUCCESS;
2167 break;
2170 state = IOUC_READ_PAGE1;
2171 break;
2173 case IOUC_READ_PAGE1:
2174 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2175 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2176 goto cleanup;
2179 num_phys = ddi_get8(page_accessp,
2180 &sasioupage1->NumPhys);
2181 ASSERT(num_phys == mpt->m_num_phys);
2182 if (num_phys > MPTSAS_MAX_PHYS) {
2183 mptsas_log(mpt, CE_WARN, "Number of phys "
2184 "supported by HBA (%d) is more than max "
2185 "supported by driver (%d). Driver will "
2186 "not attach.", num_phys,
2187 MPTSAS_MAX_PHYS);
2188 rval = DDI_FAILURE;
2189 goto cleanup;
2191 for (i = 0; i < num_phys; i++) {
2192 cpdi[i] = ddi_get32(page_accessp,
2193 &sasioupage1->PhyData[i].
2194 ControllerPhyDeviceInfo);
2195 port_flags = ddi_get8(page_accessp,
2196 &sasioupage1->PhyData[i].PortFlags);
2197 mpt->m_phy_info[i].port_num =
2198 ddi_get8(page_accessp,
2199 &sasioupage1->PhyData[i].Port);
2200 mpt->m_phy_info[i].port_flags = port_flags;
2201 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2205 state = IOUC_DONE;
2206 rval = DDI_SUCCESS;
2207 break;
2210 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2211 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2212 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2213 rval = DDI_FAILURE;
2214 goto cleanup;
2216 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2217 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2218 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2219 rval = DDI_FAILURE;
2220 goto cleanup;
2223 cleanup:
2224 if (free_recv)
2225 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2226 if (free_page)
2227 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2228 if (rval != DDI_SUCCESS) {
2229 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2230 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2232 return (rval);
2236 * mptsas_get_manufacture_page5
2238 * This function will retrieve the base WWID from the adapter. Since this
2239 * function is only called during the initialization process, use handshaking.
2242 mptsas_get_manufacture_page5(mptsas_t *mpt)
2244 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2245 ddi_dma_cookie_t page_cookie;
2246 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2247 ddi_acc_handle_t recv_accessp, page_accessp;
2248 pMpi2ConfigReply_t configreply;
2249 caddr_t recv_memp, page_memp;
2250 int recv_numbytes;
2251 pMpi2ManufacturingPage5_t m5;
2252 uint32_t flagslength;
2253 int rval = DDI_SUCCESS;
2254 uint_t iocstatus;
2255 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2257 MPTSAS_DISABLE_INTR(mpt);
2259 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2260 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2261 rval = DDI_FAILURE;
2262 goto done;
2266 * dynamically create a customized dma attribute structure
2267 * that describes the MPT's config reply page request structure.
2269 recv_dma_attrs = mpt->m_msg_dma_attr;
2270 recv_dma_attrs.dma_attr_sgllen = 1;
2271 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2273 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2274 &recv_dma_handle, &recv_accessp, &recv_memp,
2275 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2276 rval = DDI_FAILURE;
2277 goto done;
2279 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2280 free_recv = B_TRUE;
2282 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2283 configreply = (pMpi2ConfigReply_t)recv_memp;
2284 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2287 * get config reply message
2289 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2290 recv_accessp)) {
2291 rval = DDI_FAILURE;
2292 goto done;
2295 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2296 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2297 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2298 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2299 goto done;
2303 * dynamically create a customized dma attribute structure
2304 * that describes the MPT's config page structure.
2306 page_dma_attrs = mpt->m_msg_dma_attr;
2307 page_dma_attrs.dma_attr_sgllen = 1;
2308 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2310 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2311 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2312 &page_cookie) == FALSE) {
2313 rval = DDI_FAILURE;
2314 goto done;
2316 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2317 free_page = B_TRUE;
2319 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2320 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2323 * Give reply address to IOC to store config page in and send
2324 * config request out.
2327 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2328 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2329 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2330 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2331 MPI2_SGE_FLAGS_IOC_TO_HOST |
2332 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2334 if (mptsas_send_config_request_msg(mpt,
2335 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2336 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2337 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2338 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2339 flagslength, page_cookie.dmac_address)) {
2340 rval = DDI_FAILURE;
2341 goto done;
2345 * get reply view handshake
2347 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2348 recv_accessp)) {
2349 rval = DDI_FAILURE;
2350 goto done;
2353 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2354 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2355 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2356 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2357 goto done;
2360 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2363 * Fusion-MPT stores fields in little-endian format. This is
2364 * why the low-order 32 bits are stored first.
2366 mpt->un.sasaddr.m_base_wwid_lo =
2367 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2368 mpt->un.sasaddr.m_base_wwid_hi =
2369 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2371 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2372 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2373 NDBG2(("%s%d: failed to create base-wwid property",
2374 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2378 * Set the number of PHYs present.
2380 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2382 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2383 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2384 NDBG2(("%s%d: failed to create num-phys property",
2385 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2388 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2389 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2390 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2392 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2393 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2394 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2395 rval = DDI_FAILURE;
2396 goto done;
2398 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2399 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2400 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2401 rval = DDI_FAILURE;
2403 done:
2405 * free up memory
2407 if (free_recv)
2408 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2409 if (free_page)
2410 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2411 MPTSAS_ENABLE_INTR(mpt);
2413 return (rval);
2416 static int
2417 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2418 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2419 va_list ap)
2421 #ifndef __lock_lint
2422 _NOTE(ARGUNUSED(ap))
2423 #endif
2424 pMpi2SasPhyPage0_t sasphypage;
2425 int rval = DDI_SUCCESS;
2426 uint16_t *owner_devhdl, *attached_devhdl;
2427 uint8_t *attached_phy_identify;
2428 uint32_t *attached_phy_info;
2429 uint8_t *programmed_link_rate;
2430 uint8_t *hw_link_rate;
2431 uint8_t *change_count;
2432 uint32_t *phy_info;
2433 uint8_t *negotiated_link_rate;
2434 uint32_t page_address;
2436 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2437 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2438 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2439 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2440 iocstatus, iocloginfo);
2441 rval = DDI_FAILURE;
2442 return (rval);
2444 page_address = va_arg(ap, uint32_t);
2446 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2447 * are no more pages. If everything is OK up to this point but the
2448 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2449 * signal that device traversal is complete.
2451 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2452 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2453 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2454 mpt->m_done_traverse_smp = 1;
2456 rval = DDI_FAILURE;
2457 return (rval);
2459 owner_devhdl = va_arg(ap, uint16_t *);
2460 attached_devhdl = va_arg(ap, uint16_t *);
2461 attached_phy_identify = va_arg(ap, uint8_t *);
2462 attached_phy_info = va_arg(ap, uint32_t *);
2463 programmed_link_rate = va_arg(ap, uint8_t *);
2464 hw_link_rate = va_arg(ap, uint8_t *);
2465 change_count = va_arg(ap, uint8_t *);
2466 phy_info = va_arg(ap, uint32_t *);
2467 negotiated_link_rate = va_arg(ap, uint8_t *);
2469 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2471 *owner_devhdl =
2472 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2473 *attached_devhdl =
2474 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2475 *attached_phy_identify =
2476 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2477 *attached_phy_info =
2478 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2479 *programmed_link_rate =
2480 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2481 *hw_link_rate =
2482 ddi_get8(accessp, &sasphypage->HwLinkRate);
2483 *change_count =
2484 ddi_get8(accessp, &sasphypage->ChangeCount);
2485 *phy_info =
2486 ddi_get32(accessp, &sasphypage->PhyInfo);
2487 *negotiated_link_rate =
2488 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2490 return (rval);
2494 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2495 * and SAS address.
2498 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2499 smhba_info_t *info)
2501 int rval = DDI_SUCCESS;
2503 ASSERT(mutex_owned(&mpt->m_mutex));
2506 * Get the header and config page. reply contains the reply frame,
2507 * which holds status info for the request.
2509 rval = mptsas_access_config_page(mpt,
2510 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2511 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2512 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2513 &info->attached_devhdl, &info->attached_phy_identify,
2514 &info->attached_phy_info, &info->programmed_link_rate,
2515 &info->hw_link_rate, &info->change_count,
2516 &info->phy_info, &info->negotiated_link_rate);
2518 return (rval);
2521 static int
2522 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2523 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2524 va_list ap)
2526 #ifndef __lock_lint
2527 _NOTE(ARGUNUSED(ap))
2528 #endif
2529 pMpi2SasPhyPage1_t sasphypage;
2530 int rval = DDI_SUCCESS;
2532 uint32_t *invalid_dword_count;
2533 uint32_t *running_disparity_error_count;
2534 uint32_t *loss_of_dword_sync_count;
2535 uint32_t *phy_reset_problem_count;
2536 uint32_t page_address;
2538 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2539 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2540 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2541 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2542 iocstatus, iocloginfo);
2543 rval = DDI_FAILURE;
2544 return (rval);
2546 page_address = va_arg(ap, uint32_t);
2548 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2549 * are no more pages. If everything is OK up to this point but the
2550 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2551 * signal that device traversal is complete.
2553 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2554 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2555 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2556 mpt->m_done_traverse_smp = 1;
2558 rval = DDI_FAILURE;
2559 return (rval);
2562 invalid_dword_count = va_arg(ap, uint32_t *);
2563 running_disparity_error_count = va_arg(ap, uint32_t *);
2564 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2565 phy_reset_problem_count = va_arg(ap, uint32_t *);
2567 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2569 *invalid_dword_count =
2570 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2571 *running_disparity_error_count =
2572 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2573 *loss_of_dword_sync_count =
2574 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2575 *phy_reset_problem_count =
2576 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2578 return (rval);
2582 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2583 * and SAS address.
2586 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2587 smhba_info_t *info)
2589 int rval = DDI_SUCCESS;
2591 ASSERT(mutex_owned(&mpt->m_mutex));
2594 * Get the header and config page. reply contains the reply frame,
2595 * which holds status info for the request.
2597 rval = mptsas_access_config_page(mpt,
2598 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2599 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2600 mptsas_sasphypage_1_cb, page_address,
2601 &info->invalid_dword_count,
2602 &info->running_disparity_error_count,
2603 &info->loss_of_dword_sync_count,
2604 &info->phy_reset_problem_count);
2606 return (rval);
2609 * mptsas_get_manufacture_page0
2611 * This function will retrieve the base
2612 * Chip name, Board Name,Board Trace number from the adapter.
2613 * Since this function is only called during the
2614 * initialization process, use handshaking.
2617 mptsas_get_manufacture_page0(mptsas_t *mpt)
2619 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2620 ddi_dma_cookie_t page_cookie;
2621 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2622 ddi_acc_handle_t recv_accessp, page_accessp;
2623 pMpi2ConfigReply_t configreply;
2624 caddr_t recv_memp, page_memp;
2625 int recv_numbytes;
2626 pMpi2ManufacturingPage0_t m0;
2627 uint32_t flagslength;
2628 int rval = DDI_SUCCESS;
2629 uint_t iocstatus;
2630 uint8_t i = 0;
2631 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2633 MPTSAS_DISABLE_INTR(mpt);
2635 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2636 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2637 rval = DDI_FAILURE;
2638 goto done;
2642 * dynamically create a customized dma attribute structure
2643 * that describes the MPT's config reply page request structure.
2645 recv_dma_attrs = mpt->m_msg_dma_attr;
2646 recv_dma_attrs.dma_attr_sgllen = 1;
2647 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2649 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2650 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2651 NULL) == FALSE) {
2652 rval = DDI_FAILURE;
2653 goto done;
2655 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2656 free_recv = B_TRUE;
2658 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2659 configreply = (pMpi2ConfigReply_t)recv_memp;
2660 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2663 * get config reply message
2665 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2666 recv_accessp)) {
2667 rval = DDI_FAILURE;
2668 goto done;
2671 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2672 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2673 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2674 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2675 goto done;
2679 * dynamically create a customized dma attribute structure
2680 * that describes the MPT's config page structure.
2682 page_dma_attrs = mpt->m_msg_dma_attr;
2683 page_dma_attrs.dma_attr_sgllen = 1;
2684 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2686 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2687 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2688 &page_cookie) == FALSE) {
2689 rval = DDI_FAILURE;
2690 goto done;
2692 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2693 free_page = B_TRUE;
2695 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2696 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2699 * Give reply address to IOC to store config page in and send
2700 * config request out.
2703 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2704 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2705 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2706 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2707 MPI2_SGE_FLAGS_IOC_TO_HOST |
2708 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2710 if (mptsas_send_config_request_msg(mpt,
2711 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2712 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2713 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2714 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2715 flagslength, page_cookie.dmac_address)) {
2716 rval = DDI_FAILURE;
2717 goto done;
2721 * get reply view handshake
2723 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2724 recv_accessp)) {
2725 rval = DDI_FAILURE;
2726 goto done;
2729 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2730 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2731 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2732 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2733 goto done;
2736 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2739 * Fusion-MPT stores fields in little-endian format. This is
2740 * why the low-order 32 bits are stored first.
2743 for (i = 0; i < 16; i++) {
2744 mpt->m_MANU_page0.ChipName[i] =
2745 ddi_get8(page_accessp,
2746 (uint8_t *)(void *)&m0->ChipName[i]);
2749 for (i = 0; i < 8; i++) {
2750 mpt->m_MANU_page0.ChipRevision[i] =
2751 ddi_get8(page_accessp,
2752 (uint8_t *)(void *)&m0->ChipRevision[i]);
2755 for (i = 0; i < 16; i++) {
2756 mpt->m_MANU_page0.BoardName[i] =
2757 ddi_get8(page_accessp,
2758 (uint8_t *)(void *)&m0->BoardName[i]);
2761 for (i = 0; i < 16; i++) {
2762 mpt->m_MANU_page0.BoardAssembly[i] =
2763 ddi_get8(page_accessp,
2764 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2767 for (i = 0; i < 16; i++) {
2768 mpt->m_MANU_page0.BoardTracerNumber[i] =
2769 ddi_get8(page_accessp,
2770 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2773 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2774 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2775 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2776 rval = DDI_FAILURE;
2777 goto done;
2779 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2780 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2781 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2782 rval = DDI_FAILURE;
2784 done:
2786 * free up memory
2788 if (free_recv)
2789 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2790 if (free_page)
2791 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2792 MPTSAS_ENABLE_INTR(mpt);
2794 return (rval);