1 /*
2 * CDDL HEADER START
3 *
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.
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,
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.
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 {
116 cmd->m_event_linkp = NULL;
117 *(mpt->m_ioc_event_cmdtail) = cmd;
118 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
119 }
120 }
121
122 /*
123 * remove specified cmd from the ioc event queue
124 */
125 static void
126 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
127 {
128 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
129 if (prev == cmd) {
130 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
131 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
132 }
133 cmd->m_event_linkp = NULL;
134 return;
135 }
136 while (prev != NULL) {
137 if (prev->m_event_linkp == cmd) {
138 prev->m_event_linkp = cmd->m_event_linkp;
139 if (cmd->m_event_linkp == NULL) {
140 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
141 }
142
143 cmd->m_event_linkp = NULL;
144 return;
145 }
146 prev = prev->m_event_linkp;
147 }
148 }
149
150 static m_event_struct_t *
151 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
152 {
153 m_event_struct_t *ioc_cmd = NULL;
154
155 ioc_cmd = mpt->m_ioc_event_cmdq;
156 while (ioc_cmd != NULL) {
157 if (&(ioc_cmd->m_event_cmd) == cmd) {
158 return (ioc_cmd);
159 }
160 ioc_cmd = ioc_cmd->m_event_linkp;
161 }
162 ioc_cmd = NULL;
163 return (ioc_cmd);
164 }
165
166 void
167 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
168 {
169 m_event_struct_t *ioc_cmd = NULL;
170 m_event_struct_t *ioc_cmd_tmp = NULL;
171 ioc_cmd = mpt->m_ioc_event_cmdq;
172
173 /*
174 * because the IOC event queue is resource of per instance for driver,
175 * it's not only ACK event commands used it, but also some others used
176 * it. We need destroy all ACK event commands when IOC reset, but can't
177 * disturb others.So we use filter to clear the ACK event cmd in ioc
178 * event queue, and other requests should be reserved, and they would
179 * be free by its owner.
180 */
181 while (ioc_cmd != NULL) {
182 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
183 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
184 if ((mpt->m_ioc_event_cmdq =
185 ioc_cmd->m_event_linkp) == NULL)
186 mpt->m_ioc_event_cmdtail =
187 &mpt->m_ioc_event_cmdq;
188 ioc_cmd_tmp = ioc_cmd;
189 ioc_cmd = ioc_cmd->m_event_linkp;
190 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
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;
233 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
234 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
235 ddi_put8(mpt->m_acc_req_frame_hdl,
236 &request->Header.PageType,
237 MPI2_CONFIG_PAGETYPE_EXTENDED);
238 ddi_put8(mpt->m_acc_req_frame_hdl,
239 &request->ExtPageType, config->page_type);
240 } else {
241 ddi_put8(mpt->m_acc_req_frame_hdl,
242 &request->Header.PageType, config->page_type);
243 }
244 } else {
245 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
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 /*
337 * Save the data for this request to be used in the call to start the
338 * config header request.
339 */
340 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
341 config.page_type = page_type;
342 config.page_number = page_number;
343 config.page_address = page_address;
344
345 /*
346 * Form a blank cmd/pkt to store the acknowledgement message
347 */
348 pkt->pkt_ha_private = (opaque_t)&config;
349 pkt->pkt_flags = FLAG_HEAD;
350 pkt->pkt_time = 60;
351 cmd->cmd_pkt = pkt;
352 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
353
354 /*
355 * Save the config header request message in a slot.
356 */
357 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
358 cmd->cmd_flags |= CFLAG_PREPARED;
359 mptsas_start_config_page_access(mpt, cmd);
360 } else {
361 mptsas_waitq_add(mpt, cmd);
362 }
363
364 /*
365 * If this is a request for a RAID info page, or any page called during
366 * the RAID info page request, poll because these config page requests
367 * are nested. Poll to avoid data corruption due to one page's data
368 * overwriting the outer page request's data. This can happen when
369 * the mutex is released in cv_wait.
370 */
371 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
372 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
373 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
374 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
375 } else {
376 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
377 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
378 }
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: "
420 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
421 iocloginfo));
422 rval = DDI_FAILURE;
423 goto page_done;
424 }
425
426 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
427 MPI2_CONFIG_PAGETYPE_EXTENDED)
428 len = (config.ext_page_length * 4);
429 else
430 len = (config.page_length * 4);
431
432 }
433
434 if (pkt->pkt_reason == CMD_RESET) {
435 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
436 "request");
437 rval = DDI_FAILURE;
438 goto page_done;
439 }
440
441 /*
442 * Put the reply frame back on the free queue, increment the free
443 * index, and write the new index to the free index register. But only
444 * if this reply is an ADDRESS reply.
445 */
446 if (config_flags & MPTSAS_ADDRESS_REPLY) {
447 ddi_put32(mpt->m_acc_free_queue_hdl,
448 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
449 cmd->cmd_rfm);
450 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
451 DDI_DMA_SYNC_FORDEV);
452 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
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
501 /*
502 * Send the config page request. cmd is re-used from header request.
503 */
504 mptsas_start_config_page_access(mpt, cmd);
505
506 /*
507 * If this is a request for a RAID info page, or any page called during
508 * the RAID info page request, poll because these config page requests
509 * are nested. Poll to avoid data corruption due to one page's data
510 * overwriting the outer page request's data. This can happen when
511 * the mutex is released in cv_wait.
512 */
513 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
514 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
515 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
516 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
517 } else {
518 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
519 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
520 }
521 }
522
523 /*
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;
565 }
566
567 if (pkt->pkt_reason == CMD_TRAN_ERR) {
568 mptsas_log(mpt, CE_WARN, "config fma error");
569 rval = DDI_FAILURE;
570 goto page_done;
571 }
572 if (pkt->pkt_reason == CMD_RESET) {
573 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
574 rval = DDI_FAILURE;
575 goto page_done;
576 }
577
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);
703 if (polls++ > 60000) {
704 return (-1);
705 }
706 }
707 return (0);
708 }
709
710 int
711 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
712 {
713 int polls = 0;
714
715 while ((ddi_get32(mpt->m_datap,
716 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
717 drv_usecwait(1000);
718 if (polls++ > 300000) {
719 return (-1);
720 }
721 }
722 return (0);
723 }
724
725 int
726 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
727 ddi_acc_handle_t accessp)
728 {
729 int i;
730
731 /*
732 * clean pending doorbells
733 */
734 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
735 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
736 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
737 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
738
739 if (mptsas_ioc_wait_for_doorbell(mpt)) {
740 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
741 return (-1);
742 }
743
744 /*
745 * clean pending doorbells again
746 */
747 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
748
749 if (mptsas_ioc_wait_for_response(mpt)) {
750 NDBG19(("mptsas_send_handshake failed. Doorbell not "
751 "cleared\n"));
752 return (-1);
753 }
754
755 /*
756 * post handshake message
757 */
758 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
759 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
760 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
761 if (mptsas_ioc_wait_for_response(mpt)) {
762 NDBG19(("mptsas_send_handshake failed posting "
763 "message\n"));
764 return (-1);
765 }
766 }
767
768 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
769 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
770 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
771 return (-1);
772 }
773
774 return (0);
775 }
776
777 int
778 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
779 ddi_acc_handle_t accessp)
780 {
781 int i, totalbytes, bytesleft;
782 uint16_t val;
783
784 /*
785 * wait for doorbell
786 */
787 if (mptsas_ioc_wait_for_doorbell(mpt)) {
788 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
789 return (-1);
790 }
791
792 /*
793 * get first 2 bytes of handshake message to determine how much
794 * data we will be getting
795 */
796 for (i = 0; i < 2; i++, memp += 2) {
797 val = (ddi_get32(mpt->m_datap,
798 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
799 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
800 if (mptsas_ioc_wait_for_doorbell(mpt)) {
801 NDBG19(("mptsas_get_handshake failure getting initial"
802 " data\n"));
803 return (-1);
804 }
805 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
806 if (i == 1) {
807 totalbytes = (val & 0xFF) * 2;
808 }
809 }
810
811 /*
812 * If we are expecting less bytes than the message wants to send
813 * we simply save as much as we expected and then throw out the rest
814 * later
815 */
816 if (totalbytes > (numbytes / 2)) {
817 bytesleft = ((numbytes / 2) - 2);
818 } else {
819 bytesleft = (totalbytes - 2);
820 }
821
822 /*
823 * Get the rest of the data
824 */
825 for (i = 0; i < bytesleft; i++, memp += 2) {
826 val = (ddi_get32(mpt->m_datap,
827 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
828 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
829 if (mptsas_ioc_wait_for_doorbell(mpt)) {
830 NDBG19(("mptsas_get_handshake failure getting"
831 " main data\n"));
832 return (-1);
833 }
834 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
835 }
836
837 /*
838 * Sometimes the device will send more data than is expected
839 * This data is not used by us but needs to be cleared from
840 * ioc doorbell. So we just read the values and throw
841 * them out.
842 */
843 if (totalbytes > (numbytes / 2)) {
844 for (i = (numbytes / 2); i < totalbytes; i++) {
845 val = (ddi_get32(mpt->m_datap,
846 &mpt->m_reg->Doorbell) &
847 MPI2_DOORBELL_DATA_MASK);
848 ddi_put32(mpt->m_datap,
849 &mpt->m_reg->HostInterruptStatus, 0);
850 if (mptsas_ioc_wait_for_doorbell(mpt)) {
851 NDBG19(("mptsas_get_handshake failure getting "
852 "extra garbage data\n"));
853 return (-1);
854 }
855 }
856 }
857
858 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
859
860 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
861 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
862 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
863 return (-1);
864 }
865
866 return (0);
867 }
868
869 int
870 mptsas_kick_start(mptsas_t *mpt)
871 {
872 int polls = 0;
873 uint32_t diag_reg, ioc_state, saved_HCB_size;
874
875 /*
876 * Start a hard reset. Write magic number and wait 500 mSeconds.
877 */
878 MPTSAS_ENABLE_DRWE(mpt);
879 drv_usecwait(500000);
880
881 /*
882 * Read the current Diag Reg and save the Host Controlled Boot size.
883 */
884 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
885 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
886
887 /*
888 * Set Reset Adapter bit and wait 50 mSeconds.
889 */
890 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
891 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
892 drv_usecwait(50000);
893
894 /*
895 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
896 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
897 * If no more adapter (all FF's), just return failure.
898 */
899 for (polls = 0; polls < 600000; polls++) {
900 diag_reg = ddi_get32(mpt->m_datap,
901 &mpt->m_reg->HostDiagnostic);
902 if (diag_reg == 0xFFFFFFFF) {
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);
906 }
907 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
908 break;
909 }
910 drv_usecwait(500);
911 }
912 if (polls == 600000) {
913 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
914 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
915 return (DDI_FAILURE);
916 }
917
918 /*
919 * Check if adapter is in Host Boot Mode. If so, restart adapter
920 * assuming the HCB points to good FW.
921 * Set BootDeviceSel to HCDW (Host Code and Data Window).
922 */
923 if (diag_reg & MPI2_DIAG_HCB_MODE) {
924 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
925 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
926 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
927
928 /*
929 * Re-enable the HCDW.
930 */
931 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
932 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
933 }
934
935 /*
936 * Restart the adapter.
937 */
938 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
939 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
940
941 /*
942 * Disable writes to the Host Diag register.
943 */
944 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
945 MPI2_WRSEQ_FLUSH_KEY_VALUE);
946
947 /*
948 * Wait 60 seconds max for FW to come to ready state.
949 */
950 for (polls = 0; polls < 60000; polls++) {
951 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
952 if (ioc_state == 0xFFFFFFFF) {
953 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
954 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
955 return (DDI_FAILURE);
956 }
957 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
958 MPI2_IOC_STATE_READY) {
959 break;
960 }
961 drv_usecwait(1000);
962 }
963 if (polls == 60000) {
964 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
965 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
966 return (DDI_FAILURE);
967 }
968
969 /*
970 * Clear the ioc ack events queue.
971 */
972 mptsas_destroy_ioc_event_cmd(mpt);
973
974 return (DDI_SUCCESS);
975 }
976
977 int
978 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
979 {
980 int polls = 0;
981 uint32_t reset_msg;
982 uint32_t ioc_state;
983
984 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
985 /*
986 * If chip is already in ready state then there is nothing to do.
987 */
988 if (ioc_state == MPI2_IOC_STATE_READY) {
989 return (MPTSAS_NO_RESET);
990 }
991 /*
992 * If the chip is already operational, we just need to send
993 * it a message unit reset to put it back in the ready state
994 */
995 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
996 /*
997 * If the first time, try MUR anyway, because we haven't even
998 * queried the card for m_event_replay and other capabilities.
999 * Other platforms do it this way, we can still do a hard
1000 * reset if we need to, MUR takes less time than a full
1001 * adapter reset, and there are reports that some HW
1002 * combinations will lock up when receiving a hard reset.
1003 */
1004 if ((first_time || mpt->m_event_replay) &&
1005 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
1006 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1007 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
1008 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
1009 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
1010 if (mptsas_ioc_wait_for_response(mpt)) {
1011 NDBG19(("mptsas_ioc_reset failure sending "
1012 "message_unit_reset\n"));
1013 goto hard_reset;
1014 }
1015
1016 /*
1017 * Wait no more than 60 seconds for chip to become
1018 * ready.
1019 */
1020 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1021 MPI2_IOC_STATE_READY) == 0x0) {
1022 drv_usecwait(1000);
1023 if (polls++ > 60000) {
1024 goto hard_reset;
1025 }
1026 }
1027
1028 /*
1029 * Save the last reset mode done on IOC which will be
1030 * helpful while resuming from suspension.
1031 */
1032 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1033
1034 /*
1035 * the message unit reset would do reset operations
1036 * clear reply and request queue, so we should clear
1037 * ACK event cmd.
1038 */
1039 mptsas_destroy_ioc_event_cmd(mpt);
1040 return (MPTSAS_SUCCESS_MUR);
1041 }
1042 }
1043 hard_reset:
1044 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1045 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1046 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1047 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1048 return (MPTSAS_RESET_FAIL);
1049 }
1050 return (MPTSAS_SUCCESS_HARDRESET);
1051 }
1052
1053
1054 int
1055 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1056 struct scsi_pkt **pkt)
1057 {
1058 m_event_struct_t *ioc_cmd = NULL;
1059
1060 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1061 if (ioc_cmd == NULL) {
1062 return (DDI_FAILURE);
1063 }
1064 ioc_cmd->m_event_linkp = NULL;
1065 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1066 *cmd = &(ioc_cmd->m_event_cmd);
1067 *pkt = &(ioc_cmd->m_event_pkt);
1068
1069 return (DDI_SUCCESS);
1070 }
1071
1072 void
1073 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1074 {
1075 m_event_struct_t *ioc_cmd = NULL;
1076
1077 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1078 if (ioc_cmd == NULL) {
1079 return;
1080 }
1081
1082 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1083 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1084 ioc_cmd = NULL;
1085 }
1086
1087 /*
1088 * NOTE: We should be able to queue TM requests in the controller to make this
1089 * a lot faster. If resetting all targets, for example, we can load the hi
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;
1132 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1133 pkt->pkt_time = 60;
1134 pkt->pkt_address.a_target = dev_handle;
1135 pkt->pkt_address.a_lun = (uchar_t)lun;
1136 cmd->cmd_pkt = pkt;
1137 cmd->cmd_scblen = 1;
1138 cmd->cmd_flags = CFLAG_TM_CMD;
1139 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1140
1141 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1142
1143 /*
1144 * Store the TM message in memory location corresponding to the TM slot
1145 * number.
1146 */
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) {
1355 mptsas_log(mpt, CE_WARN,
1356 "(unable to allocate dma resource.");
1357 mptsas_return_to_pool(mpt, cmd);
1358 return (-1);
1359 }
1360
1361 bzero(flsh_memp, size);
1362
1363 for (i = 0; i < size; i++) {
1364 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1365 }
1366 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1367
1368 /*
1369 * form a cmd/pkt to store the fw download message
1370 */
1371 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1372 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1373 pkt->pkt_ha_private = (opaque_t)cmd;
1374 pkt->pkt_flags = FLAG_HEAD;
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;
1556 uint16_t *pdevhdl;
1557 uint32_t page_address;
1558
1559 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1560 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1561 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1562 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1563 iocstatus, iocloginfo);
1564 rval = DDI_FAILURE;
1565 return (rval);
1566 }
1567 page_address = va_arg(ap, uint32_t);
1568 /*
1569 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1570 * are no more pages. If everything is OK up to this point but the
1571 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1572 * signal that device traversal is complete.
1573 */
1574 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1575 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1576 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1577 mpt->m_done_traverse_smp = 1;
1578 }
1579 rval = DDI_FAILURE;
1580 return (rval);
1581 }
1582 devhdl = va_arg(ap, uint16_t *);
1583 sas_wwn = va_arg(ap, uint64_t *);
1584 phymask = va_arg(ap, mptsas_phymask_t *);
1585 pdevhdl = va_arg(ap, uint16_t *);
1586
1587 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1588
1589 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1590 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1591 *phymask = mptsas_physport_to_phymask(mpt, physport);
1592 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1593 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1594 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1595 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1596 }
1597 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1598 *sas_wwn = LE_64(*sas_wwn);
1599
1600 return (rval);
1601 }
1602
1603 /*
1604 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1605 * and SAS address.
1606 */
1607 int
1608 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1609 mptsas_smp_t *info)
1610 {
1611 int rval = DDI_SUCCESS;
1612
1613 ASSERT(mutex_owned(&mpt->m_mutex));
1614
1615 /*
1616 * Get the header and config page. reply contains the reply frame,
1617 * which holds status info for the request.
1618 */
1619 rval = mptsas_access_config_page(mpt,
1620 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1621 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1622 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1623 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1624
1625 return (rval);
1626 }
1627
1628 static int
1629 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1630 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1631 va_list ap)
1632 {
1633 #ifndef __lock_lint
1634 _NOTE(ARGUNUSED(ap))
1635 #endif
1636 int rval = DDI_SUCCESS, i;
1637 uint8_t *sas_addr = NULL;
1638 uint64_t *sas_wwn;
1639 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1640 uint8_t *portwidth;
1641 pMpi2SasPortPage0_t sasportpage;
1642
1643 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1644 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1645 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1646 iocstatus, iocloginfo);
1647 rval = DDI_FAILURE;
1648 return (rval);
1649 }
1650 sas_wwn = va_arg(ap, uint64_t *);
1651 portwidth = va_arg(ap, uint8_t *);
1652
1653 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1654 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1655 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1656 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1657 }
1658 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1659 *sas_wwn = LE_64(*sas_wwn);
1660 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1661 return (rval);
1662 }
1663
1664 /*
1665 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1666 * and port width.
1667 */
1668 int
1669 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1670 uint64_t *sas_wwn, uint8_t *portwidth)
1671 {
1672 int rval = DDI_SUCCESS;
1673
1674 ASSERT(mutex_owned(&mpt->m_mutex));
1675
1676 /*
1677 * Get the header and config page. reply contains the reply frame,
1678 * which holds status info for the request.
1679 */
1680 rval = mptsas_access_config_page(mpt,
1681 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1682 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1683 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1684
1685 return (rval);
1686 }
1687
1688 static int
1689 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1690 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1691 va_list ap)
1692 {
1693 #ifndef __lock_lint
1694 _NOTE(ARGUNUSED(ap))
1695 #endif
1696 int rval = DDI_SUCCESS;
1697 pMpi2SasIOUnitPage0_t sasioupage0;
1698 int i, num_phys;
1699 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1700 uint8_t port_flags;
1701
1702 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1703 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1704 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1705 iocstatus, iocloginfo);
1706 rval = DDI_FAILURE;
1707 return (rval);
1708 }
1709 readpage1 = va_arg(ap, uint32_t *);
1710 retrypage0 = va_arg(ap, uint32_t *);
1711
1712 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1713
1714 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1715 /*
1716 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1717 * was initially set. This should never change throughout the life of
1718 * the driver.
1719 */
1720 ASSERT(num_phys == mpt->m_num_phys);
1721 for (i = 0; i < num_phys; i++) {
1722 cpdi[i] = ddi_get32(accessp,
1723 &sasioupage0->PhyData[i].
1724 ControllerPhyDeviceInfo);
1725 port_flags = ddi_get8(accessp,
1726 &sasioupage0->PhyData[i].PortFlags);
1727 mpt->m_phy_info[i].port_num =
1728 ddi_get8(accessp,
1729 &sasioupage0->PhyData[i].Port);
1730 mpt->m_phy_info[i].ctrl_devhdl =
1731 ddi_get16(accessp, &sasioupage0->
1732 PhyData[i].ControllerDevHandle);
1733 mpt->m_phy_info[i].attached_devhdl =
1734 ddi_get16(accessp, &sasioupage0->
1735 PhyData[i].AttachedDevHandle);
1736 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1737 mpt->m_phy_info[i].port_flags = port_flags;
1738
1739 if (port_flags & DISCOVERY_IN_PROGRESS) {
1740 *retrypage0 = *retrypage0 + 1;
1741 break;
1742 } else {
1743 *retrypage0 = 0;
1744 }
1745 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1746 /*
1747 * some PHY configuration described in
1748 * SAS IO Unit Page1
1749 */
1750 *readpage1 = 1;
1751 }
1752 }
1753
1754 return (rval);
1755 }
1756
1757 static int
1758 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1759 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1760 va_list ap)
1761 {
1762 #ifndef __lock_lint
1763 _NOTE(ARGUNUSED(ap))
1764 #endif
1765 int rval = DDI_SUCCESS;
1766 pMpi2SasIOUnitPage1_t sasioupage1;
1767 int i, num_phys;
1768 uint32_t cpdi[MPTSAS_MAX_PHYS];
1769 uint8_t port_flags;
1770
1771 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1772 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1773 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1774 iocstatus, iocloginfo);
1775 rval = DDI_FAILURE;
1776 return (rval);
1777 }
1778
1779 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1780 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1781 /*
1782 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1783 * was initially set. This should never change throughout the life of
1784 * the driver.
1785 */
1786 ASSERT(num_phys == mpt->m_num_phys);
1787 for (i = 0; i < num_phys; i++) {
1788 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1789 ControllerPhyDeviceInfo);
1790 port_flags = ddi_get8(accessp,
1791 &sasioupage1->PhyData[i].PortFlags);
1792 mpt->m_phy_info[i].port_num =
1793 ddi_get8(accessp,
1794 &sasioupage1->PhyData[i].Port);
1795 mpt->m_phy_info[i].port_flags = port_flags;
1796 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1797 }
1798 return (rval);
1799 }
1800
1801 /*
1802 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1803 * page1 to update the PHY information. This is the message passing method of
1804 * this function which should be called except during initialization.
1805 */
1806 int
1807 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1808 {
1809 int rval = DDI_SUCCESS, state;
1810 uint32_t readpage1 = 0, retrypage0 = 0;
1811
1812 ASSERT(mutex_owned(&mpt->m_mutex));
1813
1814 /*
1815 * Now we cycle through the state machine. Here's what happens:
1816 * 1. Read IO unit page 0 and set phy information
1817 * 2. See if Read IO unit page1 is needed because of port configuration
1818 * 3. Read IO unit page 1 and update phy information.
1819 */
1820 state = IOUC_READ_PAGE0;
1821 while (state != IOUC_DONE) {
1822 if (state == IOUC_READ_PAGE0) {
1823 rval = mptsas_access_config_page(mpt,
1824 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1825 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1826 mptsas_sasiou_page_0_cb, &readpage1,
1827 &retrypage0);
1828 } else if (state == IOUC_READ_PAGE1) {
1829 rval = mptsas_access_config_page(mpt,
1830 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1831 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1832 mptsas_sasiou_page_1_cb);
1833 }
1834
1835 if (rval == DDI_SUCCESS) {
1836 switch (state) {
1837 case IOUC_READ_PAGE0:
1838 /*
1839 * retry 30 times if discovery is in process
1840 */
1841 if (retrypage0 && (retrypage0 < 30)) {
1842 drv_usecwait(1000 * 100);
1843 state = IOUC_READ_PAGE0;
1844 break;
1845 } else if (retrypage0 == 30) {
1846 mptsas_log(mpt, CE_WARN,
1847 "!Discovery in progress, can't "
1848 "verify IO unit config, then "
1849 "after 30 times retry, give "
1850 "up!");
1851 state = IOUC_DONE;
1852 rval = DDI_FAILURE;
1853 break;
1854 }
1855
1856 if (readpage1 == 0) {
1857 state = IOUC_DONE;
1858 rval = DDI_SUCCESS;
1859 break;
1860 }
1861
1862 state = IOUC_READ_PAGE1;
1863 break;
1864
1865 case IOUC_READ_PAGE1:
1866 state = IOUC_DONE;
1867 rval = DDI_SUCCESS;
1868 break;
1869 }
1870 } else {
1871 return (rval);
1872 }
1873 }
1874
1875 return (rval);
1876 }
1877
1878 static int
1879 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1880 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1881 va_list ap)
1882 {
1883 #ifndef __lock_lint
1884 _NOTE(ARGUNUSED(ap))
1885 #endif
1886 pMpi2BiosPage3_t sasbiospage;
1887 int rval = DDI_SUCCESS;
1888 uint32_t *bios_version;
1889
1890 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1891 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1892 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1893 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1894 rval = DDI_FAILURE;
1895 return (rval);
1896 }
1897 bios_version = va_arg(ap, uint32_t *);
1898 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1899 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1900
1901 return (rval);
1902 }
1903
1904 /*
1905 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1906 * other information in this page is not needed, just ignore it.
1907 */
1908 int
1909 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1910 {
1911 int rval = DDI_SUCCESS;
1912
1913 ASSERT(mutex_owned(&mpt->m_mutex));
1914
1915 /*
1916 * Get the header and config page. reply contains the reply frame,
1917 * which holds status info for the request.
1918 */
1919 rval = mptsas_access_config_page(mpt,
1920 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1921 0, mptsas_biospage_3_cb, bios_version);
1922
1923 return (rval);
1924 }
1925
1926 /*
1927 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1928 * page1 to update the PHY information. This is the handshaking version of
1929 * this function, which should be called during initialization only.
1930 */
1931 int
1932 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1933 {
1934 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1935 ddi_dma_cookie_t page_cookie;
1936 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1937 ddi_acc_handle_t recv_accessp, page_accessp;
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
2060 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2061 recv_accessp)) {
2062 goto cleanup;
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) {
2104 case IOUC_READ_PAGE0:
2105 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2106 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2107 goto cleanup;
2108 }
2109
2110 num_phys = ddi_get8(page_accessp,
2111 &sasioupage0->NumPhys);
2112 ASSERT(num_phys == mpt->m_num_phys);
2113 if (num_phys > MPTSAS_MAX_PHYS) {
2114 mptsas_log(mpt, CE_WARN, "Number of phys "
2115 "supported by HBA (%d) is more than max "
2116 "supported by driver (%d). Driver will "
2117 "not attach.", num_phys,
2118 MPTSAS_MAX_PHYS);
2119 rval = DDI_FAILURE;
2120 goto cleanup;
2121 }
2122 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2123 cpdi[i] = ddi_get32(page_accessp,
2124 &sasioupage0->PhyData[i].
2125 ControllerPhyDeviceInfo);
2126 port_flags = ddi_get8(page_accessp,
2127 &sasioupage0->PhyData[i].PortFlags);
2128
2129 mpt->m_phy_info[i].port_num =
2130 ddi_get8(page_accessp,
2131 &sasioupage0->PhyData[i].Port);
2132 mpt->m_phy_info[i].ctrl_devhdl =
2133 ddi_get16(page_accessp, &sasioupage0->
2134 PhyData[i].ControllerDevHandle);
2135 mpt->m_phy_info[i].attached_devhdl =
2136 ddi_get16(page_accessp, &sasioupage0->
2137 PhyData[i].AttachedDevHandle);
2138 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2139 mpt->m_phy_info[i].port_flags = port_flags;
2140
2141 if (port_flags & DISCOVERY_IN_PROGRESS) {
2142 retrypage0++;
2143 NDBG20(("Discovery in progress, can't "
2144 "verify IO unit config, then NO.%d"
2145 " times retry", retrypage0));
2146 break;
2147 } else {
2148 retrypage0 = 0;
2149 }
2150 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2151 /*
2152 * some PHY configuration described in
2153 * SAS IO Unit Page1
2154 */
2155 readpage1 = 1;
2156 }
2157 }
2158
2159 /*
2160 * retry 30 times if discovery is in process
2161 */
2162 if (retrypage0 && (retrypage0 < 30)) {
2163 drv_usecwait(1000 * 100);
2164 state = IOUC_READ_PAGE0;
2165 break;
2166 } else if (retrypage0 == 30) {
2167 mptsas_log(mpt, CE_WARN,
2168 "!Discovery in progress, can't "
2169 "verify IO unit config, then after"
2170 " 30 times retry, give up!");
2171 state = IOUC_DONE;
2172 rval = DDI_FAILURE;
2173 break;
2174 }
2175
2176 if (readpage1 == 0) {
2177 state = IOUC_DONE;
2178 rval = DDI_SUCCESS;
2179 break;
2180 }
2181
2182 state = IOUC_READ_PAGE1;
2183 break;
2184
2185 case IOUC_READ_PAGE1:
2186 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2187 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2188 goto cleanup;
2189 }
2190
2191 num_phys = ddi_get8(page_accessp,
2192 &sasioupage1->NumPhys);
2193 ASSERT(num_phys == mpt->m_num_phys);
2194 if (num_phys > MPTSAS_MAX_PHYS) {
2195 mptsas_log(mpt, CE_WARN, "Number of phys "
2196 "supported by HBA (%d) is more than max "
2197 "supported by driver (%d). Driver will "
2198 "not attach.", num_phys,
2199 MPTSAS_MAX_PHYS);
2200 rval = DDI_FAILURE;
2201 goto cleanup;
2202 }
2203 for (i = 0; i < num_phys; i++) {
2204 cpdi[i] = ddi_get32(page_accessp,
2205 &sasioupage1->PhyData[i].
2206 ControllerPhyDeviceInfo);
2207 port_flags = ddi_get8(page_accessp,
2208 &sasioupage1->PhyData[i].PortFlags);
2209 mpt->m_phy_info[i].port_num =
2210 ddi_get8(page_accessp,
2211 &sasioupage1->PhyData[i].Port);
2212 mpt->m_phy_info[i].port_flags = port_flags;
2213 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2214
2215 }
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
2375 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2376
2377 /*
2378 * Fusion-MPT stores fields in little-endian format. This is
2379 * why the low-order 32 bits are stored first.
2380 */
2381 mpt->un.sasaddr.m_base_wwid_lo =
2382 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2383 mpt->un.sasaddr.m_base_wwid_hi =
2384 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2385
2386 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2387 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2388 NDBG2(("%s%d: failed to create base-wwid property",
2389 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2390 }
2391
2392 /*
2393 * Set the number of PHYs present.
2394 */
2395 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2396
2397 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2398 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2399 NDBG2(("%s%d: failed to create num-phys property",
2400 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2401 }
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;
2445 uint8_t *hw_link_rate;
2446 uint8_t *change_count;
2447 uint32_t *phy_info;
2448 uint8_t *negotiated_link_rate;
2449 uint32_t page_address;
2450
2451 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2452 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2453 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2454 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2455 iocstatus, iocloginfo);
2456 rval = DDI_FAILURE;
2457 return (rval);
2458 }
2459 page_address = va_arg(ap, uint32_t);
2460 /*
2461 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2462 * are no more pages. If everything is OK up to this point but the
2463 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2464 * signal that device traversal is complete.
2465 */
2466 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2467 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2468 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2469 mpt->m_done_traverse_smp = 1;
2470 }
2471 rval = DDI_FAILURE;
2472 return (rval);
2473 }
2474 owner_devhdl = va_arg(ap, uint16_t *);
2475 attached_devhdl = va_arg(ap, uint16_t *);
2476 attached_phy_identify = va_arg(ap, uint8_t *);
2477 attached_phy_info = va_arg(ap, uint32_t *);
2478 programmed_link_rate = va_arg(ap, uint8_t *);
2479 hw_link_rate = va_arg(ap, uint8_t *);
2480 change_count = va_arg(ap, uint8_t *);
2481 phy_info = va_arg(ap, uint32_t *);
2482 negotiated_link_rate = va_arg(ap, uint8_t *);
2483
2484 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2485
2486 *owner_devhdl =
2487 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2488 *attached_devhdl =
2489 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2490 *attached_phy_identify =
2491 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2492 *attached_phy_info =
2493 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2494 *programmed_link_rate =
2495 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2496 *hw_link_rate =
2497 ddi_get8(accessp, &sasphypage->HwLinkRate);
2498 *change_count =
2499 ddi_get8(accessp, &sasphypage->ChangeCount);
2500 *phy_info =
2501 ddi_get32(accessp, &sasphypage->PhyInfo);
2502 *negotiated_link_rate =
2503 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2504
2505 return (rval);
2506 }
2507
2508 /*
2509 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2510 * and SAS address.
2511 */
2512 int
2513 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2514 smhba_info_t *info)
2515 {
2516 int rval = DDI_SUCCESS;
2517
2518 ASSERT(mutex_owned(&mpt->m_mutex));
2519
2520 /*
2521 * Get the header and config page. reply contains the reply frame,
2522 * which holds status info for the request.
2523 */
2524 rval = mptsas_access_config_page(mpt,
2525 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2526 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2527 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2528 &info->attached_devhdl, &info->attached_phy_identify,
2529 &info->attached_phy_info, &info->programmed_link_rate,
2530 &info->hw_link_rate, &info->change_count,
2531 &info->phy_info, &info->negotiated_link_rate);
2532
2533 return (rval);
2534 }
2535
2536 static int
2537 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2538 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2539 va_list ap)
2540 {
2541 #ifndef __lock_lint
2542 _NOTE(ARGUNUSED(ap))
2543 #endif
2544 pMpi2SasPhyPage1_t sasphypage;
2545 int rval = DDI_SUCCESS;
2546
2547 uint32_t *invalid_dword_count;
2548 uint32_t *running_disparity_error_count;
2549 uint32_t *loss_of_dword_sync_count;
2550 uint32_t *phy_reset_problem_count;
2551 uint32_t page_address;
2552
2553 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2554 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2555 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2556 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2557 iocstatus, iocloginfo);
2558 rval = DDI_FAILURE;
2559 return (rval);
2560 }
2561 page_address = va_arg(ap, uint32_t);
2562 /*
2563 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2564 * are no more pages. If everything is OK up to this point but the
2565 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2566 * signal that device traversal is complete.
2567 */
2568 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2569 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2570 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2571 mpt->m_done_traverse_smp = 1;
2572 }
2573 rval = DDI_FAILURE;
2574 return (rval);
2575 }
2576
2577 invalid_dword_count = va_arg(ap, uint32_t *);
2578 running_disparity_error_count = va_arg(ap, uint32_t *);
2579 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2580 phy_reset_problem_count = va_arg(ap, uint32_t *);
2581
2582 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2583
2584 *invalid_dword_count =
2585 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2586 *running_disparity_error_count =
2587 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2588 *loss_of_dword_sync_count =
2589 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2590 *phy_reset_problem_count =
2591 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2592
2593 return (rval);
2594 }
2595
2596 /*
2597 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2598 * and SAS address.
2599 */
2600 int
2601 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2602 smhba_info_t *info)
2603 {
2604 int rval = DDI_SUCCESS;
2605
2606 ASSERT(mutex_owned(&mpt->m_mutex));
2607
2608 /*
2609 * Get the header and config page. reply contains the reply frame,
2610 * which holds status info for the request.
2611 */
2612 rval = mptsas_access_config_page(mpt,
2613 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2614 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2615 mptsas_sasphypage_1_cb, page_address,
2616 &info->invalid_dword_count,
2617 &info->running_disparity_error_count,
2618 &info->loss_of_dword_sync_count,
2619 &info->phy_reset_problem_count);
2620
2621 return (rval);
2622 }
2623 /*
2624 * mptsas_get_manufacture_page0
2625 *
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
2751 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2752
2753 /*
2754 * Fusion-MPT stores fields in little-endian format. This is
2755 * why the low-order 32 bits are stored first.
2756 */
2757
2758 for (i = 0; i < 16; i++) {
2759 mpt->m_MANU_page0.ChipName[i] =
2760 ddi_get8(page_accessp,
2761 (uint8_t *)(void *)&m0->ChipName[i]);
2762 }
2763
2764 for (i = 0; i < 8; i++) {
2765 mpt->m_MANU_page0.ChipRevision[i] =
2766 ddi_get8(page_accessp,
2767 (uint8_t *)(void *)&m0->ChipRevision[i]);
2768 }
2769
2770 for (i = 0; i < 16; i++) {
2771 mpt->m_MANU_page0.BoardName[i] =
2772 ddi_get8(page_accessp,
2773 (uint8_t *)(void *)&m0->BoardName[i]);
2774 }
2775
2776 for (i = 0; i < 16; i++) {
2777 mpt->m_MANU_page0.BoardAssembly[i] =
2778 ddi_get8(page_accessp,
2779 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2780 }
2781
2782 for (i = 0; i < 16; i++) {
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 }