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 2014 OmniTI Computer Consulting, Inc. All rights reserved.
26 * Copyright (c) 2014, Tegile Systems 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_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()
81
82 /*
83 * private header files.
84 */
85 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
86 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
87
88 /*
89 * FMA header files.
90 */
91 #include <sys/fm/io/ddi.h>
92
93 /*
94 * prototypes
95 */
96 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
97 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
98 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
99 struct mptsas_cmd *cmd);
100
101 /*
102 * add ioc evnet cmd into the queue
103 */
104 static void
105 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
106 {
107 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
108 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
109 mpt->m_ioc_event_cmdq = cmd;
110 } else {
111 cmd->m_event_linkp = NULL;
112 *(mpt->m_ioc_event_cmdtail) = cmd;
113 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
114 }
115 }
116
117 /*
118 * remove specified cmd from the ioc event queue
119 */
120 static void
121 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
122 {
123 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
124 if (prev == cmd) {
125 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
126 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
127 }
128 cmd->m_event_linkp = NULL;
129 return;
130 }
131 while (prev != NULL) {
132 if (prev->m_event_linkp == cmd) {
133 prev->m_event_linkp = cmd->m_event_linkp;
134 if (cmd->m_event_linkp == NULL) {
135 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
136 }
137
138 cmd->m_event_linkp = NULL;
139 return;
140 }
141 prev = prev->m_event_linkp;
142 }
143 }
144
145 static m_event_struct_t *
146 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
147 {
148 m_event_struct_t *ioc_cmd = NULL;
149
150 ioc_cmd = mpt->m_ioc_event_cmdq;
151 while (ioc_cmd != NULL) {
152 if (&(ioc_cmd->m_event_cmd) == cmd) {
153 return (ioc_cmd);
154 }
155 ioc_cmd = ioc_cmd->m_event_linkp;
156 }
157 ioc_cmd = NULL;
158 return (ioc_cmd);
159 }
160
161 void
162 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
163 {
164 m_event_struct_t *ioc_cmd = NULL;
165 m_event_struct_t *ioc_cmd_tmp = NULL;
166 ioc_cmd = mpt->m_ioc_event_cmdq;
167
168 /*
169 * because the IOC event queue is resource of per instance for driver,
170 * it's not only ACK event commands used it, but also some others used
171 * it. We need destroy all ACK event commands when IOC reset, but can't
172 * disturb others.So we use filter to clear the ACK event cmd in ioc
173 * event queue, and other requests should be reserved, and they would
174 * be free by its owner.
175 */
176 while (ioc_cmd != NULL) {
177 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
178 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
179 if ((mpt->m_ioc_event_cmdq =
180 ioc_cmd->m_event_linkp) == NULL)
181 mpt->m_ioc_event_cmdtail =
182 &mpt->m_ioc_event_cmdq;
183 ioc_cmd_tmp = ioc_cmd;
184 ioc_cmd = ioc_cmd->m_event_linkp;
185 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
186 } else {
187 /*
188 * it's not ack cmd, so continue to check next one
189 */
190
191 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
192 ioc_cmd = ioc_cmd->m_event_linkp;
193 }
194
195 }
196 }
197
198 void
199 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
200 {
201 pMpi2ConfigRequest_t request;
202 pMpi2SGESimple64_t sge;
203 struct scsi_pkt *pkt = cmd->cmd_pkt;
204 mptsas_config_request_t *config = pkt->pkt_ha_private;
205 uint8_t direction;
206 uint32_t length, flagslength, request_desc_low;
207
208 ASSERT(mutex_owned(&mpt->m_mutex));
209
210 /*
211 * Point to the correct message and clear it as well as the global
212 * config page memory.
213 */
214 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
215 (mpt->m_req_frame_size * cmd->cmd_slot));
216 bzero(request, mpt->m_req_frame_size);
217
218 /*
219 * Form the request message.
220 */
221 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
222 MPI2_FUNCTION_CONFIG);
223 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
224 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
225 length = 0;
226 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
227 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
228 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
229 ddi_put8(mpt->m_acc_req_frame_hdl,
230 &request->Header.PageType,
231 MPI2_CONFIG_PAGETYPE_EXTENDED);
232 ddi_put8(mpt->m_acc_req_frame_hdl,
233 &request->ExtPageType, config->page_type);
234 } else {
235 ddi_put8(mpt->m_acc_req_frame_hdl,
236 &request->Header.PageType, config->page_type);
237 }
238 } else {
239 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
240 config->ext_page_type);
241 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
242 config->ext_page_length);
243 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
244 config->page_type);
245 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
246 config->page_length);
247 ddi_put8(mpt->m_acc_req_frame_hdl,
248 &request->Header.PageVersion, config->page_version);
249 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
250 MPI2_CONFIG_PAGETYPE_EXTENDED) {
251 length = config->ext_page_length * 4;
252 } else {
253 length = config->page_length * 4;
254 }
255
256 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
257 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
258 }
259 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
260 (uint32_t)cmd->cmd_dma_addr);
261 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
262 (uint32_t)(cmd->cmd_dma_addr >> 32));
263 }
264 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
265 config->page_number);
266 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
267 config->page_address);
268 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
269 MPI2_SGE_FLAGS_END_OF_BUFFER |
270 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
271 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
272 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
273 direction |
274 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
275 flagslength |= length;
276 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
277
278 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
279 DDI_DMA_SYNC_FORDEV);
280 request_desc_low = (cmd->cmd_slot << 16) +
281 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
282 cmd->cmd_rfm = NULL;
283 MPTSAS_START_CMD(mpt, request_desc_low, 0);
284 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
285 DDI_SUCCESS) ||
286 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
287 DDI_SUCCESS)) {
288 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
289 }
290 }
291
292 int
293 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
294 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
295 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
296 {
297 va_list ap;
298 ddi_dma_attr_t attrs;
299 ddi_dma_cookie_t cookie;
300 ddi_acc_handle_t accessp;
301 size_t len = 0;
302 mptsas_config_request_t config;
303 int rval = DDI_SUCCESS, config_flags = 0;
304 mptsas_cmd_t *cmd;
305 struct scsi_pkt *pkt;
306 pMpi2ConfigReply_t reply;
307 uint16_t iocstatus = 0;
308 uint32_t iocloginfo;
309 caddr_t page_memp;
310 boolean_t free_dma = B_FALSE;
311
312 va_start(ap, callback);
313 ASSERT(mutex_owned(&mpt->m_mutex));
314
315 /*
316 * Get a command from the pool.
317 */
318 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
319 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
320 "page request");
321 rval = DDI_FAILURE;
322 goto page_done;
323 }
324 config_flags |= MPTSAS_REQUEST_POOL_CMD;
325
326 bzero((caddr_t)cmd, sizeof (*cmd));
327 bzero((caddr_t)pkt, scsi_pkt_size());
328 bzero((caddr_t)&config, sizeof (config));
329
330 /*
331 * Save the data for this request to be used in the call to start the
332 * config header request.
333 */
334 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
335 config.page_type = page_type;
336 config.page_number = page_number;
337 config.page_address = page_address;
338
339 /*
340 * Form a blank cmd/pkt to store the acknowledgement message
341 */
342 pkt->pkt_ha_private = (opaque_t)&config;
343 pkt->pkt_flags = FLAG_HEAD;
344 pkt->pkt_time = 60;
345 cmd->cmd_pkt = pkt;
346 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
347
348 /*
349 * Save the config header request message in a slot.
350 */
351 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
352 cmd->cmd_flags |= CFLAG_PREPARED;
353 mptsas_start_config_page_access(mpt, cmd);
354 } else {
355 mptsas_waitq_add(mpt, cmd);
356 }
357
358 /*
359 * If this is a request for a RAID info page, or any page called during
360 * the RAID info page request, poll because these config page requests
361 * are nested. Poll to avoid data corruption due to one page's data
362 * overwriting the outer page request's data. This can happen when
363 * the mutex is released in cv_wait.
364 */
365 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
366 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
367 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
368 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
369 } else {
370 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
371 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
372 }
373 }
374
375 /*
376 * Check if the header request completed without timing out
377 */
378 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
379 mptsas_log(mpt, CE_WARN, "config header request timeout");
380 rval = DDI_FAILURE;
381 goto page_done;
382 }
383
384 /*
385 * cmd_rfm points to the reply message if a reply was given. Check the
386 * IOCStatus to make sure everything went OK with the header request.
387 */
388 if (cmd->cmd_rfm) {
389 config_flags |= MPTSAS_ADDRESS_REPLY;
390 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
391 DDI_DMA_SYNC_FORCPU);
392 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
393 - mpt->m_reply_frame_dma_addr));
394 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
395 &reply->Header.PageType);
396 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
397 &reply->Header.PageNumber);
398 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
399 &reply->Header.PageLength);
400 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
401 &reply->Header.PageVersion);
402 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
403 &reply->ExtPageType);
404 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
405 &reply->ExtPageLength);
406
407 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
408 &reply->IOCStatus);
409 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
410 &reply->IOCLogInfo);
411
412 if (iocstatus) {
413 NDBG13(("mptsas_access_config_page header: "
414 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
415 iocloginfo));
416 rval = DDI_FAILURE;
417 goto page_done;
418 }
419
420 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
421 MPI2_CONFIG_PAGETYPE_EXTENDED)
422 len = (config.ext_page_length * 4);
423 else
424 len = (config.page_length * 4);
425
426 }
427
428 if (pkt->pkt_reason == CMD_RESET) {
429 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
430 "request");
431 rval = DDI_FAILURE;
432 goto page_done;
433 }
434
435 /*
436 * Put the reply frame back on the free queue, increment the free
437 * index, and write the new index to the free index register. But only
438 * if this reply is an ADDRESS reply.
439 */
440 if (config_flags & MPTSAS_ADDRESS_REPLY) {
441 ddi_put32(mpt->m_acc_free_queue_hdl,
442 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
443 cmd->cmd_rfm);
444 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
445 DDI_DMA_SYNC_FORDEV);
446 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
447 mpt->m_free_index = 0;
448 }
449 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
450 mpt->m_free_index);
451 config_flags &= (~MPTSAS_ADDRESS_REPLY);
452 }
453
454 /*
455 * Allocate DMA buffer here. Store the info regarding this buffer in
456 * the cmd struct so that it can be used for this specific command and
457 * de-allocated after the command completes. The size of the reply
458 * will not be larger than the reply frame size.
459 */
460 attrs = mpt->m_msg_dma_attr;
461 attrs.dma_attr_sgllen = 1;
462 attrs.dma_attr_granular = (uint32_t)len;
463
464 if (mptsas_dma_addr_create(mpt, attrs,
465 &cmd->cmd_dmahandle, &accessp, &page_memp,
466 len, &cookie) == FALSE) {
467 rval = DDI_FAILURE;
468 mptsas_log(mpt, CE_WARN,
469 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
470 goto page_done;
471 }
472 /* NOW we can safely call mptsas_dma_addr_destroy(). */
473 free_dma = B_TRUE;
474
475 cmd->cmd_dma_addr = cookie.dmac_laddress;
476 bzero(page_memp, len);
477
478 /*
479 * Save the data for this request to be used in the call to start the
480 * config page read
481 */
482 config.action = action;
483 config.page_address = page_address;
484
485 /*
486 * Re-use the cmd that was used to get the header. Reset some of the
487 * values.
488 */
489 bzero((caddr_t)pkt, scsi_pkt_size());
490 pkt->pkt_ha_private = (opaque_t)&config;
491 pkt->pkt_flags = FLAG_HEAD;
492 pkt->pkt_time = 60;
493 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
494
495 /*
496 * Send the config page request. cmd is re-used from header request.
497 */
498 mptsas_start_config_page_access(mpt, cmd);
499
500 /*
501 * If this is a request for a RAID info page, or any page called during
502 * the RAID info page request, poll because these config page requests
503 * are nested. Poll to avoid data corruption due to one page's data
504 * overwriting the outer page request's data. This can happen when
505 * the mutex is released in cv_wait.
506 */
507 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
508 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
509 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
510 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
511 } else {
512 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
513 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
514 }
515 }
516
517 /*
518 * Check if the request completed without timing out
519 */
520 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
521 mptsas_log(mpt, CE_WARN, "config page request timeout");
522 rval = DDI_FAILURE;
523 goto page_done;
524 }
525
526 /*
527 * cmd_rfm points to the reply message if a reply was given. The reply
528 * frame and the config page are returned from this function in the
529 * param list.
530 */
531 if (cmd->cmd_rfm) {
532 config_flags |= MPTSAS_ADDRESS_REPLY;
533 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
534 DDI_DMA_SYNC_FORCPU);
535 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
536 DDI_DMA_SYNC_FORCPU);
537 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
538 - mpt->m_reply_frame_dma_addr));
539 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
540 &reply->IOCStatus);
541 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
542 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
543 &reply->IOCLogInfo);
544 }
545
546 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
547 rval = DDI_FAILURE;
548 goto page_done;
549 }
550
551 mptsas_fma_check(mpt, cmd);
552 /*
553 * Check the DMA/ACC handles and then free the DMA buffer.
554 */
555 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
556 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
557 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
558 rval = DDI_FAILURE;
559 }
560
561 if (pkt->pkt_reason == CMD_TRAN_ERR) {
562 mptsas_log(mpt, CE_WARN, "config fma error");
563 rval = DDI_FAILURE;
564 goto page_done;
565 }
566 if (pkt->pkt_reason == CMD_RESET) {
567 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
568 rval = DDI_FAILURE;
569 goto page_done;
570 }
571
572 page_done:
573 va_end(ap);
574 /*
575 * Put the reply frame back on the free queue, increment the free
576 * index, and write the new index to the free index register. But only
577 * if this reply is an ADDRESS reply.
578 */
579 if (config_flags & MPTSAS_ADDRESS_REPLY) {
580 ddi_put32(mpt->m_acc_free_queue_hdl,
581 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
582 cmd->cmd_rfm);
583 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
584 DDI_DMA_SYNC_FORDEV);
585 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
586 mpt->m_free_index = 0;
587 }
588 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
589 mpt->m_free_index);
590 }
591
592 if (free_dma)
593 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
594
595 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
596 mptsas_remove_cmd(mpt, cmd);
597 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
598 }
599 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
600 mptsas_return_to_pool(mpt, cmd);
601
602 if (config_flags & MPTSAS_CMD_TIMEOUT) {
603 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
604 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
605 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
606 }
607 }
608
609 return (rval);
610 }
611
612 int
613 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
614 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
615 uint8_t pagelength, uint32_t SGEflagslength, uint32_t SGEaddress32)
616 {
617 pMpi2ConfigRequest_t config;
618 int send_numbytes;
619
620 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
621 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
622 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
623 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
624 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
625 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
626 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
627 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
628 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
629 ddi_put32(mpt->m_hshk_acc_hdl,
630 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
631 ddi_put32(mpt->m_hshk_acc_hdl,
632 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
633 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
634
635 /*
636 * Post message via handshake
637 */
638 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
639 mpt->m_hshk_acc_hdl)) {
640 return (-1);
641 }
642 return (0);
643 }
644
645 int
646 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
647 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
648 uint8_t pageversion, uint16_t extpagelength,
649 uint32_t SGEflagslength, uint32_t SGEaddress32)
650 {
651 pMpi2ConfigRequest_t config;
652 int send_numbytes;
653
654 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
655 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
656 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
657 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
658 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
659 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
660 MPI2_CONFIG_PAGETYPE_EXTENDED);
661 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
662 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
663 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
664 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
665 ddi_put32(mpt->m_hshk_acc_hdl,
666 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
667 ddi_put32(mpt->m_hshk_acc_hdl,
668 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
669 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
670
671 /*
672 * Post message via handshake
673 */
674 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
675 mpt->m_hshk_acc_hdl)) {
676 return (-1);
677 }
678 return (0);
679 }
680
681 int
682 mptsas_ioc_wait_for_response(mptsas_t *mpt)
683 {
684 int polls = 0;
685
686 while ((ddi_get32(mpt->m_datap,
687 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
688 drv_usecwait(1000);
689 if (polls++ > 60000) {
690 return (-1);
691 }
692 }
693 return (0);
694 }
695
696 int
697 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
698 {
699 int polls = 0;
700
701 while ((ddi_get32(mpt->m_datap,
702 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
703 drv_usecwait(1000);
704 if (polls++ > 300000) {
705 return (-1);
706 }
707 }
708 return (0);
709 }
710
711 int
712 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
713 ddi_acc_handle_t accessp)
714 {
715 int i;
716
717 /*
718 * clean pending doorbells
719 */
720 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
721 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
722 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
723 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
724
725 if (mptsas_ioc_wait_for_doorbell(mpt)) {
726 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
727 return (-1);
728 }
729
730 /*
731 * clean pending doorbells again
732 */
733 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
734
735 if (mptsas_ioc_wait_for_response(mpt)) {
736 NDBG19(("mptsas_send_handshake failed. Doorbell not "
737 "cleared\n"));
738 return (-1);
739 }
740
741 /*
742 * post handshake message
743 */
744 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
745 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
746 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
747 if (mptsas_ioc_wait_for_response(mpt)) {
748 NDBG19(("mptsas_send_handshake failed posting "
749 "message\n"));
750 return (-1);
751 }
752 }
753
754 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
755 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
756 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
757 return (-1);
758 }
759
760 return (0);
761 }
762
763 int
764 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
765 ddi_acc_handle_t accessp)
766 {
767 int i, totalbytes, bytesleft;
768 uint16_t val;
769
770 /*
771 * wait for doorbell
772 */
773 if (mptsas_ioc_wait_for_doorbell(mpt)) {
774 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
775 return (-1);
776 }
777
778 /*
779 * get first 2 bytes of handshake message to determine how much
780 * data we will be getting
781 */
782 for (i = 0; i < 2; i++, memp += 2) {
783 val = (ddi_get32(mpt->m_datap,
784 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
785 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
786 if (mptsas_ioc_wait_for_doorbell(mpt)) {
787 NDBG19(("mptsas_get_handshake failure getting initial"
788 " data\n"));
789 return (-1);
790 }
791 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
792 if (i == 1) {
793 totalbytes = (val & 0xFF) * 2;
794 }
795 }
796
797 /*
798 * If we are expecting less bytes than the message wants to send
799 * we simply save as much as we expected and then throw out the rest
800 * later
801 */
802 if (totalbytes > (numbytes / 2)) {
803 bytesleft = ((numbytes / 2) - 2);
804 } else {
805 bytesleft = (totalbytes - 2);
806 }
807
808 /*
809 * Get the rest of the data
810 */
811 for (i = 0; i < bytesleft; i++, memp += 2) {
812 val = (ddi_get32(mpt->m_datap,
813 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
814 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
815 if (mptsas_ioc_wait_for_doorbell(mpt)) {
816 NDBG19(("mptsas_get_handshake failure getting"
817 " main data\n"));
818 return (-1);
819 }
820 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
821 }
822
823 /*
824 * Sometimes the device will send more data than is expected
825 * This data is not used by us but needs to be cleared from
826 * ioc doorbell. So we just read the values and throw
827 * them out.
828 */
829 if (totalbytes > (numbytes / 2)) {
830 for (i = (numbytes / 2); i < totalbytes; i++) {
831 val = (ddi_get32(mpt->m_datap,
832 &mpt->m_reg->Doorbell) &
833 MPI2_DOORBELL_DATA_MASK);
834 ddi_put32(mpt->m_datap,
835 &mpt->m_reg->HostInterruptStatus, 0);
836 if (mptsas_ioc_wait_for_doorbell(mpt)) {
837 NDBG19(("mptsas_get_handshake failure getting "
838 "extra garbage data\n"));
839 return (-1);
840 }
841 }
842 }
843
844 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
845
846 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
847 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
848 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
849 return (-1);
850 }
851
852 return (0);
853 }
854
855 int
856 mptsas_kick_start(mptsas_t *mpt)
857 {
858 int polls = 0;
859 uint32_t diag_reg, ioc_state, saved_HCB_size;
860
861 /*
862 * Start a hard reset. Write magic number and wait 500 mSeconds.
863 */
864 MPTSAS_ENABLE_DRWE(mpt);
865 drv_usecwait(500000);
866
867 /*
868 * Read the current Diag Reg and save the Host Controlled Boot size.
869 */
870 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
871 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
872
873 /*
874 * Set Reset Adapter bit and wait 50 mSeconds.
875 */
876 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
877 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
878 drv_usecwait(50000);
879
880 /*
881 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
882 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
883 * If no more adapter (all FF's), just return failure.
884 */
885 for (polls = 0; polls < 600000; polls++) {
886 diag_reg = ddi_get32(mpt->m_datap,
887 &mpt->m_reg->HostDiagnostic);
888 if (diag_reg == 0xFFFFFFFF) {
889 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
890 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
891 return (DDI_FAILURE);
892 }
893 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
894 break;
895 }
896 drv_usecwait(500);
897 }
898 if (polls == 600000) {
899 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
900 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
901 return (DDI_FAILURE);
902 }
903
904 /*
905 * Check if adapter is in Host Boot Mode. If so, restart adapter
906 * assuming the HCB points to good FW.
907 * Set BootDeviceSel to HCDW (Host Code and Data Window).
908 */
909 if (diag_reg & MPI2_DIAG_HCB_MODE) {
910 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
911 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
912 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
913
914 /*
915 * Re-enable the HCDW.
916 */
917 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
918 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
919 }
920
921 /*
922 * Restart the adapter.
923 */
924 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
925 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
926
927 /*
928 * Disable writes to the Host Diag register.
929 */
930 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
931 MPI2_WRSEQ_FLUSH_KEY_VALUE);
932
933 /*
934 * Wait 60 seconds max for FW to come to ready state.
935 */
936 for (polls = 0; polls < 60000; polls++) {
937 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
938 if (ioc_state == 0xFFFFFFFF) {
939 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
940 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
941 return (DDI_FAILURE);
942 }
943 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
944 MPI2_IOC_STATE_READY) {
945 break;
946 }
947 drv_usecwait(1000);
948 }
949 if (polls == 60000) {
950 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
951 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
952 return (DDI_FAILURE);
953 }
954
955 /*
956 * Clear the ioc ack events queue.
957 */
958 mptsas_destroy_ioc_event_cmd(mpt);
959
960 return (DDI_SUCCESS);
961 }
962
963 int
964 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
965 {
966 int polls = 0;
967 uint32_t reset_msg;
968 uint32_t ioc_state;
969
970 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
971 /*
972 * If chip is already in ready state then there is nothing to do.
973 */
974 if (ioc_state == MPI2_IOC_STATE_READY) {
975 return (MPTSAS_NO_RESET);
976 }
977 /*
978 * If the chip is already operational, we just need to send
979 * it a message unit reset to put it back in the ready state
980 */
981 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
982 /*
983 * If the first time, try MUR anyway, because we haven't even
984 * queried the card for m_event_replay and other capabilities.
985 * Other platforms do it this way, we can still do a hard
986 * reset if we need to, MUR takes less time than a full
987 * adapter reset, and there are reports that some HW
988 * combinations will lock up when receiving a hard reset.
989 */
990 if ((first_time || mpt->m_event_replay) &&
991 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
992 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
993 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
994 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
995 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
996 if (mptsas_ioc_wait_for_response(mpt)) {
997 NDBG19(("mptsas_ioc_reset failure sending "
998 "message_unit_reset\n"));
999 goto hard_reset;
1000 }
1001
1002 /*
1003 * Wait no more than 60 seconds for chip to become
1004 * ready.
1005 */
1006 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1007 MPI2_IOC_STATE_READY) == 0x0) {
1008 drv_usecwait(1000);
1009 if (polls++ > 60000) {
1010 goto hard_reset;
1011 }
1012 }
1013
1014 /*
1015 * Save the last reset mode done on IOC which will be
1016 * helpful while resuming from suspension.
1017 */
1018 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1019
1020 /*
1021 * the message unit reset would do reset operations
1022 * clear reply and request queue, so we should clear
1023 * ACK event cmd.
1024 */
1025 mptsas_destroy_ioc_event_cmd(mpt);
1026 return (MPTSAS_SUCCESS_MUR);
1027 }
1028 }
1029 hard_reset:
1030 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1031 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1032 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1033 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1034 return (MPTSAS_RESET_FAIL);
1035 }
1036 return (MPTSAS_SUCCESS_HARDRESET);
1037 }
1038
1039
1040 int
1041 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1042 struct scsi_pkt **pkt)
1043 {
1044 m_event_struct_t *ioc_cmd = NULL;
1045
1046 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1047 if (ioc_cmd == NULL) {
1048 return (DDI_FAILURE);
1049 }
1050 ioc_cmd->m_event_linkp = NULL;
1051 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1052 *cmd = &(ioc_cmd->m_event_cmd);
1053 *pkt = &(ioc_cmd->m_event_pkt);
1054
1055 return (DDI_SUCCESS);
1056 }
1057
1058 void
1059 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1060 {
1061 m_event_struct_t *ioc_cmd = NULL;
1062
1063 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1064 if (ioc_cmd == NULL) {
1065 return;
1066 }
1067
1068 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1069 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1070 ioc_cmd = NULL;
1071 }
1072
1073 /*
1074 * NOTE: We should be able to queue TM requests in the controller to make this
1075 * a lot faster. If resetting all targets, for example, we can load the hi
1076 * priority queue with its limit and the controller will reply as they are
1077 * completed. This way, we don't have to poll for one reply at a time.
1078 * Think about enhancing this later.
1079 */
1080 int
1081 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1082 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1083 {
1084 /*
1085 * In order to avoid allocating variables on the stack,
1086 * we make use of the pre-existing mptsas_cmd_t and
1087 * scsi_pkt which are included in the mptsas_t which
1088 * is passed to this routine.
1089 */
1090
1091 pMpi2SCSITaskManagementRequest_t task;
1092 int rval = FALSE;
1093 mptsas_cmd_t *cmd;
1094 struct scsi_pkt *pkt;
1095 mptsas_slots_t *slots = mpt->m_active;
1096 uint32_t request_desc_low, i;
1097 pMPI2DefaultReply_t reply_msg;
1098
1099 /*
1100 * Can't start another task management routine.
1101 */
1102 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1103 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1104 " command at a time\n");
1105 return (FALSE);
1106 }
1107
1108 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1109 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1110
1111 bzero((caddr_t)cmd, sizeof (*cmd));
1112 bzero((caddr_t)pkt, scsi_pkt_size());
1113
1114 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1115 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1116 pkt->pkt_ha_private = (opaque_t)cmd;
1117 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1118 pkt->pkt_time = 60;
1119 pkt->pkt_address.a_target = dev_handle;
1120 pkt->pkt_address.a_lun = (uchar_t)lun;
1121 cmd->cmd_pkt = pkt;
1122 cmd->cmd_scblen = 1;
1123 cmd->cmd_flags = CFLAG_TM_CMD;
1124 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1125
1126 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1127
1128 /*
1129 * Store the TM message in memory location corresponding to the TM slot
1130 * number.
1131 */
1132 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1133 (mpt->m_req_frame_size * cmd->cmd_slot));
1134 bzero(task, mpt->m_req_frame_size);
1135
1136 /*
1137 * form message for requested task
1138 */
1139 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1140 MPI2_FUNCTION_SCSI_TASK_MGMT);
1141
1142 /*
1143 * Set the task type
1144 */
1145 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1146
1147 /*
1148 * Send TM request using High Priority Queue.
1149 */
1150 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1151 DDI_DMA_SYNC_FORDEV);
1152 request_desc_low = (cmd->cmd_slot << 16) +
1153 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1154 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1155 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1156
1157 if (pkt->pkt_reason == CMD_INCOMPLETE)
1158 rval = FALSE;
1159
1160 /*
1161 * If a reply frame was used and there is a reply buffer to copy the
1162 * reply data into, copy it. If this fails, log a message, but don't
1163 * fail the TM request.
1164 */
1165 if (cmd->cmd_rfm && reply) {
1166 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1167 DDI_DMA_SYNC_FORCPU);
1168 reply_msg = (pMPI2DefaultReply_t)
1169 (mpt->m_reply_frame + (cmd->cmd_rfm -
1170 mpt->m_reply_frame_dma_addr));
1171 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1172 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1173 }
1174 mutex_exit(&mpt->m_mutex);
1175 for (i = 0; i < reply_size; i++) {
1176 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1177 mode)) {
1178 mptsas_log(mpt, CE_WARN, "failed to copy out "
1179 "reply data for TM request");
1180 break;
1181 }
1182 }
1183 mutex_enter(&mpt->m_mutex);
1184 }
1185
1186 /*
1187 * clear the TM slot before returning
1188 */
1189 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1190
1191 /*
1192 * If we lost our task management command
1193 * we need to reset the ioc
1194 */
1195 if (rval == FALSE) {
1196 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1197 "try to reset ioc to recovery!");
1198 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1199 if (mptsas_restart_ioc(mpt)) {
1200 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1201 rval = FAILED;
1202 }
1203 }
1204
1205 return (rval);
1206 }
1207
1208 /*
1209 * Complete firmware download frame for v2.0 cards.
1210 */
1211 static void
1212 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1213 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1214 ddi_dma_cookie_t flsh_cookie)
1215 {
1216 pMpi2FWDownloadTCSGE_t tcsge;
1217 pMpi2SGESimple64_t sge;
1218 uint32_t flagslength;
1219
1220 ddi_put8(acc_hdl, &fwdownload->Function,
1221 MPI2_FUNCTION_FW_DOWNLOAD);
1222 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1223 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1224 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1225 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1226
1227 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1228 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1229 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1230 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1231 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1232 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1233
1234 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1235 flagslength = size;
1236 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1237 MPI2_SGE_FLAGS_END_OF_BUFFER |
1238 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1239 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1240 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1241 MPI2_SGE_FLAGS_HOST_TO_IOC |
1242 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1243 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1244 ddi_put32(acc_hdl, &sge->Address.Low,
1245 flsh_cookie.dmac_address);
1246 ddi_put32(acc_hdl, &sge->Address.High,
1247 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1248 }
1249
1250 /*
1251 * Complete firmware download frame for v2.5 cards.
1252 */
1253 static void
1254 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1255 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1256 ddi_dma_cookie_t flsh_cookie)
1257 {
1258 pMpi2IeeeSgeSimple64_t sge;
1259 uint8_t flags;
1260
1261 ddi_put8(acc_hdl, &fwdownload->Function,
1262 MPI2_FUNCTION_FW_DOWNLOAD);
1263 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1264 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1265 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1266 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1267
1268 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1269 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1270
1271 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1272 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1273 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1274 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1275 ddi_put8(acc_hdl, &sge->Flags, flags);
1276 ddi_put32(acc_hdl, &sge->Length, size);
1277 ddi_put32(acc_hdl, &sge->Address.Low,
1278 flsh_cookie.dmac_address);
1279 ddi_put32(acc_hdl, &sge->Address.High,
1280 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1281 }
1282
1283 static int mptsas_enable_mpi25_flashupdate = 0;
1284
1285 int
1286 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1287 uint8_t type, int mode)
1288 {
1289
1290 /*
1291 * In order to avoid allocating variables on the stack,
1292 * we make use of the pre-existing mptsas_cmd_t and
1293 * scsi_pkt which are included in the mptsas_t which
1294 * is passed to this routine.
1295 */
1296
1297 ddi_dma_attr_t flsh_dma_attrs;
1298 ddi_dma_cookie_t flsh_cookie;
1299 ddi_dma_handle_t flsh_dma_handle;
1300 ddi_acc_handle_t flsh_accessp;
1301 caddr_t memp, flsh_memp;
1302 mptsas_cmd_t *cmd;
1303 struct scsi_pkt *pkt;
1304 int i;
1305 int rvalue = 0;
1306 uint32_t request_desc_low;
1307
1308 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1309 /*
1310 * The code is there but not tested yet.
1311 * User has to know there are risks here.
1312 */
1313 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1314 "Updating firmware through MPI 2.5 has not been "
1315 "tested yet!\n"
1316 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1317 return (-1);
1318 } /* Otherwise, you pay your money and you take your chances. */
1319
1320 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1321 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1322 "failed. event ack command pool is full\n");
1323 return (rvalue);
1324 }
1325
1326 bzero((caddr_t)cmd, sizeof (*cmd));
1327 bzero((caddr_t)pkt, scsi_pkt_size());
1328 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1329
1330 /*
1331 * dynamically create a customized dma attribute structure
1332 * that describes the flash file.
1333 */
1334 flsh_dma_attrs = mpt->m_msg_dma_attr;
1335 flsh_dma_attrs.dma_attr_sgllen = 1;
1336
1337 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1338 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1339 mptsas_log(mpt, CE_WARN,
1340 "(unable to allocate dma resource.");
1341 mptsas_return_to_pool(mpt, cmd);
1342 return (-1);
1343 }
1344
1345 bzero(flsh_memp, size);
1346
1347 for (i = 0; i < size; i++) {
1348 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1349 }
1350 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1351
1352 /*
1353 * form a cmd/pkt to store the fw download message
1354 */
1355 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1356 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1357 pkt->pkt_ha_private = (opaque_t)cmd;
1358 pkt->pkt_flags = FLAG_HEAD;
1359 pkt->pkt_time = 60;
1360 cmd->cmd_pkt = pkt;
1361 cmd->cmd_scblen = 1;
1362 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1363
1364 /*
1365 * Save the command in a slot
1366 */
1367 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1368 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1369 mptsas_return_to_pool(mpt, cmd);
1370 return (-1);
1371 }
1372
1373 /*
1374 * Fill in fw download message
1375 */
1376 ASSERT(cmd->cmd_slot != 0);
1377 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1378 bzero(memp, mpt->m_req_frame_size);
1379
1380 if (mpt->m_MPI25)
1381 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1382 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1383 else
1384 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1385 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1386
1387 /*
1388 * Start command
1389 */
1390 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1391 DDI_DMA_SYNC_FORDEV);
1392 request_desc_low = (cmd->cmd_slot << 16) +
1393 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1394 cmd->cmd_rfm = NULL;
1395 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1396
1397 rvalue = 0;
1398 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1399 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1400 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1401 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1402 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1403 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1404 }
1405 rvalue = -1;
1406 }
1407 mptsas_remove_cmd(mpt, cmd);
1408 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1409
1410 return (rvalue);
1411 }
1412
1413 static int
1414 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1415 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1416 va_list ap)
1417 {
1418 #ifndef __lock_lint
1419 _NOTE(ARGUNUSED(ap))
1420 #endif
1421 pMpi2SasDevicePage0_t sasdevpage;
1422 int rval = DDI_SUCCESS, i;
1423 uint8_t *sas_addr = NULL;
1424 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1425 uint16_t *devhdl, *bay_num, *enclosure;
1426 uint64_t *sas_wwn;
1427 uint32_t *dev_info;
1428 uint8_t *physport, *phynum;
1429 uint16_t *pdevhdl, *io_flags;
1430 uint32_t page_address;
1431
1432 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1433 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1434 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1435 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1436 iocstatus, iocloginfo);
1437 rval = DDI_FAILURE;
1438 return (rval);
1439 }
1440 page_address = va_arg(ap, uint32_t);
1441 /*
1442 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1443 * are no more pages. If everything is OK up to this point but the
1444 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1445 * signal that device traversal is complete.
1446 */
1447 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1448 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1449 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1450 mpt->m_done_traverse_dev = 1;
1451 }
1452 rval = DDI_FAILURE;
1453 return (rval);
1454 }
1455 devhdl = va_arg(ap, uint16_t *);
1456 sas_wwn = va_arg(ap, uint64_t *);
1457 dev_info = va_arg(ap, uint32_t *);
1458 physport = va_arg(ap, uint8_t *);
1459 phynum = va_arg(ap, uint8_t *);
1460 pdevhdl = va_arg(ap, uint16_t *);
1461 bay_num = va_arg(ap, uint16_t *);
1462 enclosure = va_arg(ap, uint16_t *);
1463 io_flags = va_arg(ap, uint16_t *);
1464
1465 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1466
1467 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1468 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1469 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1470 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1471 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1472 }
1473 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1474 *sas_wwn = LE_64(*sas_wwn);
1475 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1476 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1477 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1478 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1479 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1480 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1481
1482 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1483 /*
1484 * Leave a messages about FP cabability in the log.
1485 */
1486 mptsas_log(mpt, CE_CONT,
1487 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1488 (*io_flags &
1489 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1490 " and Enabled":" but Disabled");
1491 }
1492
1493 return (rval);
1494 }
1495
1496 /*
1497 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1498 * info and SAS address.
1499 */
1500 int
1501 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1502 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1503 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1504 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1505 {
1506 int rval = DDI_SUCCESS;
1507
1508 ASSERT(mutex_owned(&mpt->m_mutex));
1509
1510 /*
1511 * Get the header and config page. reply contains the reply frame,
1512 * which holds status info for the request.
1513 */
1514 rval = mptsas_access_config_page(mpt,
1515 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1516 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1517 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1518 dev_info, physport, phynum, pdev_handle,
1519 bay_num, enclosure, io_flags);
1520
1521 return (rval);
1522 }
1523
1524 static int
1525 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1526 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1527 va_list ap)
1528 {
1529 #ifndef __lock_lint
1530 _NOTE(ARGUNUSED(ap))
1531 #endif
1532 pMpi2ExpanderPage0_t expddevpage;
1533 int rval = DDI_SUCCESS, i;
1534 uint8_t *sas_addr = NULL;
1535 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1536 uint16_t *devhdl;
1537 uint64_t *sas_wwn;
1538 uint8_t physport;
1539 mptsas_phymask_t *phymask;
1540 uint16_t *pdevhdl;
1541 uint32_t page_address;
1542
1543 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1544 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1545 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1546 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1547 iocstatus, iocloginfo);
1548 rval = DDI_FAILURE;
1549 return (rval);
1550 }
1551 page_address = va_arg(ap, uint32_t);
1552 /*
1553 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1554 * are no more pages. If everything is OK up to this point but the
1555 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1556 * signal that device traversal is complete.
1557 */
1558 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1559 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1560 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1561 mpt->m_done_traverse_smp = 1;
1562 }
1563 rval = DDI_FAILURE;
1564 return (rval);
1565 }
1566 devhdl = va_arg(ap, uint16_t *);
1567 sas_wwn = va_arg(ap, uint64_t *);
1568 phymask = va_arg(ap, mptsas_phymask_t *);
1569 pdevhdl = va_arg(ap, uint16_t *);
1570
1571 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1572
1573 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1574 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1575 *phymask = mptsas_physport_to_phymask(mpt, physport);
1576 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1577 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1578 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1579 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1580 }
1581 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1582 *sas_wwn = LE_64(*sas_wwn);
1583
1584 return (rval);
1585 }
1586
1587 /*
1588 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1589 * and SAS address.
1590 */
1591 int
1592 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1593 mptsas_smp_t *info)
1594 {
1595 int rval = DDI_SUCCESS;
1596
1597 ASSERT(mutex_owned(&mpt->m_mutex));
1598
1599 /*
1600 * Get the header and config page. reply contains the reply frame,
1601 * which holds status info for the request.
1602 */
1603 rval = mptsas_access_config_page(mpt,
1604 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1605 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1606 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1607 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1608
1609 return (rval);
1610 }
1611
1612 static int
1613 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1614 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1615 va_list ap)
1616 {
1617 #ifndef __lock_lint
1618 _NOTE(ARGUNUSED(ap))
1619 #endif
1620 int rval = DDI_SUCCESS, i;
1621 uint8_t *sas_addr = NULL;
1622 uint64_t *sas_wwn;
1623 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1624 uint8_t *portwidth;
1625 pMpi2SasPortPage0_t sasportpage;
1626
1627 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1628 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1629 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1630 iocstatus, iocloginfo);
1631 rval = DDI_FAILURE;
1632 return (rval);
1633 }
1634 sas_wwn = va_arg(ap, uint64_t *);
1635 portwidth = va_arg(ap, uint8_t *);
1636
1637 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1638 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1639 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1640 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1641 }
1642 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1643 *sas_wwn = LE_64(*sas_wwn);
1644 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1645 return (rval);
1646 }
1647
1648 /*
1649 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1650 * and port width.
1651 */
1652 int
1653 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1654 uint64_t *sas_wwn, uint8_t *portwidth)
1655 {
1656 int rval = DDI_SUCCESS;
1657
1658 ASSERT(mutex_owned(&mpt->m_mutex));
1659
1660 /*
1661 * Get the header and config page. reply contains the reply frame,
1662 * which holds status info for the request.
1663 */
1664 rval = mptsas_access_config_page(mpt,
1665 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1666 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1667 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1668
1669 return (rval);
1670 }
1671
1672 static int
1673 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1674 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1675 va_list ap)
1676 {
1677 #ifndef __lock_lint
1678 _NOTE(ARGUNUSED(ap))
1679 #endif
1680 int rval = DDI_SUCCESS;
1681 pMpi2SasIOUnitPage0_t sasioupage0;
1682 int i, num_phys;
1683 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1684 uint8_t port_flags;
1685
1686 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1687 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1688 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1689 iocstatus, iocloginfo);
1690 rval = DDI_FAILURE;
1691 return (rval);
1692 }
1693 readpage1 = va_arg(ap, uint32_t *);
1694 retrypage0 = va_arg(ap, uint32_t *);
1695
1696 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1697
1698 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1699 /*
1700 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1701 * was initially set. This should never change throughout the life of
1702 * the driver.
1703 */
1704 ASSERT(num_phys == mpt->m_num_phys);
1705 for (i = 0; i < num_phys; i++) {
1706 cpdi[i] = ddi_get32(accessp,
1707 &sasioupage0->PhyData[i].
1708 ControllerPhyDeviceInfo);
1709 port_flags = ddi_get8(accessp,
1710 &sasioupage0->PhyData[i].PortFlags);
1711 mpt->m_phy_info[i].port_num =
1712 ddi_get8(accessp,
1713 &sasioupage0->PhyData[i].Port);
1714 mpt->m_phy_info[i].ctrl_devhdl =
1715 ddi_get16(accessp, &sasioupage0->
1716 PhyData[i].ControllerDevHandle);
1717 mpt->m_phy_info[i].attached_devhdl =
1718 ddi_get16(accessp, &sasioupage0->
1719 PhyData[i].AttachedDevHandle);
1720 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1721 mpt->m_phy_info[i].port_flags = port_flags;
1722
1723 if (port_flags & DISCOVERY_IN_PROGRESS) {
1724 *retrypage0 = *retrypage0 + 1;
1725 break;
1726 } else {
1727 *retrypage0 = 0;
1728 }
1729 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1730 /*
1731 * some PHY configuration described in
1732 * SAS IO Unit Page1
1733 */
1734 *readpage1 = 1;
1735 }
1736 }
1737
1738 return (rval);
1739 }
1740
1741 static int
1742 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1743 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1744 va_list ap)
1745 {
1746 #ifndef __lock_lint
1747 _NOTE(ARGUNUSED(ap))
1748 #endif
1749 int rval = DDI_SUCCESS;
1750 pMpi2SasIOUnitPage1_t sasioupage1;
1751 int i, num_phys;
1752 uint32_t cpdi[MPTSAS_MAX_PHYS];
1753 uint8_t port_flags;
1754
1755 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1756 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1757 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1758 iocstatus, iocloginfo);
1759 rval = DDI_FAILURE;
1760 return (rval);
1761 }
1762
1763 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1764 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1765 /*
1766 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1767 * was initially set. This should never change throughout the life of
1768 * the driver.
1769 */
1770 ASSERT(num_phys == mpt->m_num_phys);
1771 for (i = 0; i < num_phys; i++) {
1772 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1773 ControllerPhyDeviceInfo);
1774 port_flags = ddi_get8(accessp,
1775 &sasioupage1->PhyData[i].PortFlags);
1776 mpt->m_phy_info[i].port_num =
1777 ddi_get8(accessp,
1778 &sasioupage1->PhyData[i].Port);
1779 mpt->m_phy_info[i].port_flags = port_flags;
1780 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1781 }
1782 return (rval);
1783 }
1784
1785 /*
1786 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1787 * page1 to update the PHY information. This is the message passing method of
1788 * this function which should be called except during initialization.
1789 */
1790 int
1791 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1792 {
1793 int rval = DDI_SUCCESS, state;
1794 uint32_t readpage1 = 0, retrypage0 = 0;
1795
1796 ASSERT(mutex_owned(&mpt->m_mutex));
1797
1798 /*
1799 * Now we cycle through the state machine. Here's what happens:
1800 * 1. Read IO unit page 0 and set phy information
1801 * 2. See if Read IO unit page1 is needed because of port configuration
1802 * 3. Read IO unit page 1 and update phy information.
1803 */
1804 state = IOUC_READ_PAGE0;
1805 while (state != IOUC_DONE) {
1806 if (state == IOUC_READ_PAGE0) {
1807 rval = mptsas_access_config_page(mpt,
1808 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1809 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1810 mptsas_sasiou_page_0_cb, &readpage1,
1811 &retrypage0);
1812 } else if (state == IOUC_READ_PAGE1) {
1813 rval = mptsas_access_config_page(mpt,
1814 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1815 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1816 mptsas_sasiou_page_1_cb);
1817 }
1818
1819 if (rval == DDI_SUCCESS) {
1820 switch (state) {
1821 case IOUC_READ_PAGE0:
1822 /*
1823 * retry 30 times if discovery is in process
1824 */
1825 if (retrypage0 && (retrypage0 < 30)) {
1826 drv_usecwait(1000 * 100);
1827 state = IOUC_READ_PAGE0;
1828 break;
1829 } else if (retrypage0 == 30) {
1830 mptsas_log(mpt, CE_WARN,
1831 "!Discovery in progress, can't "
1832 "verify IO unit config, then "
1833 "after 30 times retry, give "
1834 "up!");
1835 state = IOUC_DONE;
1836 rval = DDI_FAILURE;
1837 break;
1838 }
1839
1840 if (readpage1 == 0) {
1841 state = IOUC_DONE;
1842 rval = DDI_SUCCESS;
1843 break;
1844 }
1845
1846 state = IOUC_READ_PAGE1;
1847 break;
1848
1849 case IOUC_READ_PAGE1:
1850 state = IOUC_DONE;
1851 rval = DDI_SUCCESS;
1852 break;
1853 }
1854 } else {
1855 return (rval);
1856 }
1857 }
1858
1859 return (rval);
1860 }
1861
1862 static int
1863 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1864 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1865 va_list ap)
1866 {
1867 #ifndef __lock_lint
1868 _NOTE(ARGUNUSED(ap))
1869 #endif
1870 pMpi2BiosPage3_t sasbiospage;
1871 int rval = DDI_SUCCESS;
1872 uint32_t *bios_version;
1873
1874 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1875 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1876 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1877 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1878 rval = DDI_FAILURE;
1879 return (rval);
1880 }
1881 bios_version = va_arg(ap, uint32_t *);
1882 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1883 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1884
1885 return (rval);
1886 }
1887
1888 /*
1889 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1890 * other information in this page is not needed, just ignore it.
1891 */
1892 int
1893 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1894 {
1895 int rval = DDI_SUCCESS;
1896
1897 ASSERT(mutex_owned(&mpt->m_mutex));
1898
1899 /*
1900 * Get the header and config page. reply contains the reply frame,
1901 * which holds status info for the request.
1902 */
1903 rval = mptsas_access_config_page(mpt,
1904 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1905 0, mptsas_biospage_3_cb, bios_version);
1906
1907 return (rval);
1908 }
1909
1910 /*
1911 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1912 * page1 to update the PHY information. This is the handshaking version of
1913 * this function, which should be called during initialization only.
1914 */
1915 int
1916 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1917 {
1918 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1919 ddi_dma_cookie_t page_cookie;
1920 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1921 ddi_acc_handle_t recv_accessp, page_accessp;
1922 pMpi2ConfigReply_t configreply;
1923 pMpi2SasIOUnitPage0_t sasioupage0;
1924 pMpi2SasIOUnitPage1_t sasioupage1;
1925 int recv_numbytes;
1926 caddr_t recv_memp, page_memp;
1927 int i, num_phys, start_phy = 0;
1928 int page0_size =
1929 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1930 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1931 int page1_size =
1932 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1933 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1934 uint32_t flags_length;
1935 uint32_t cpdi[MPTSAS_MAX_PHYS];
1936 uint32_t readpage1 = 0, retrypage0 = 0;
1937 uint16_t iocstatus;
1938 uint8_t port_flags, page_number, action;
1939 uint32_t reply_size = 256; /* Big enough for any page */
1940 uint_t state;
1941 int rval = DDI_FAILURE;
1942 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1943
1944 /*
1945 * Initialize our "state machine". This is a bit convoluted,
1946 * but it keeps us from having to do the ddi allocations numerous
1947 * times.
1948 */
1949
1950 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1951 ASSERT(mutex_owned(&mpt->m_mutex));
1952 state = IOUC_READ_PAGE0;
1953
1954 /*
1955 * dynamically create a customized dma attribute structure
1956 * that describes mpt's config reply page request structure.
1957 */
1958 recv_dma_attrs = mpt->m_msg_dma_attr;
1959 recv_dma_attrs.dma_attr_sgllen = 1;
1960 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1961
1962 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1963 &recv_dma_handle, &recv_accessp, &recv_memp,
1964 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1965 mptsas_log(mpt, CE_WARN,
1966 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1967 goto cleanup;
1968 }
1969 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1970 free_recv = B_TRUE;
1971
1972 page_dma_attrs = mpt->m_msg_dma_attr;
1973 page_dma_attrs.dma_attr_sgllen = 1;
1974 page_dma_attrs.dma_attr_granular = reply_size;
1975
1976 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1977 &page_dma_handle, &page_accessp, &page_memp,
1978 reply_size, &page_cookie) == FALSE) {
1979 mptsas_log(mpt, CE_WARN,
1980 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1981 goto cleanup;
1982 }
1983 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1984 free_page = B_TRUE;
1985
1986 /*
1987 * Now we cycle through the state machine. Here's what happens:
1988 * 1. Read IO unit page 0 and set phy information
1989 * 2. See if Read IO unit page1 is needed because of port configuration
1990 * 3. Read IO unit page 1 and update phy information.
1991 */
1992
1993 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1994 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1995
1996 while (state != IOUC_DONE) {
1997 switch (state) {
1998 case IOUC_READ_PAGE0:
1999 page_number = 0;
2000 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2001 flags_length = (uint32_t)page0_size;
2002 flags_length |= ((uint32_t)(
2003 MPI2_SGE_FLAGS_LAST_ELEMENT |
2004 MPI2_SGE_FLAGS_END_OF_BUFFER |
2005 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2006 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2007 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2008 MPI2_SGE_FLAGS_IOC_TO_HOST |
2009 MPI2_SGE_FLAGS_END_OF_LIST) <<
2010 MPI2_SGE_FLAGS_SHIFT);
2011
2012 break;
2013
2014 case IOUC_READ_PAGE1:
2015 page_number = 1;
2016 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2017 flags_length = (uint32_t)page1_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_32_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 default:
2030 break;
2031 }
2032
2033 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2034 configreply = (pMpi2ConfigReply_t)recv_memp;
2035 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2036
2037 if (mptsas_send_extended_config_request_msg(mpt,
2038 MPI2_CONFIG_ACTION_PAGE_HEADER,
2039 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2040 0, page_number, 0, 0, 0, 0)) {
2041 goto cleanup;
2042 }
2043
2044 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2045 recv_accessp)) {
2046 goto cleanup;
2047 }
2048
2049 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2050 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2051
2052 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2053 mptsas_log(mpt, CE_WARN,
2054 "mptsas_get_sas_io_unit_page_hndshk: read page "
2055 "header iocstatus = 0x%x", iocstatus);
2056 goto cleanup;
2057 }
2058
2059 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2060 bzero(page_memp, reply_size);
2061 }
2062
2063 if (mptsas_send_extended_config_request_msg(mpt, action,
2064 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2065 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2066 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2067 flags_length, page_cookie.dmac_address)) {
2068 goto cleanup;
2069 }
2070
2071 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2072 recv_accessp)) {
2073 goto cleanup;
2074 }
2075
2076 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2077 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2078
2079 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2080 mptsas_log(mpt, CE_WARN,
2081 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2082 "config failed for action %d, iocstatus = 0x%x",
2083 action, iocstatus);
2084 goto cleanup;
2085 }
2086
2087 switch (state) {
2088 case IOUC_READ_PAGE0:
2089 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2090 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2091 goto cleanup;
2092 }
2093
2094 num_phys = ddi_get8(page_accessp,
2095 &sasioupage0->NumPhys);
2096 ASSERT(num_phys == mpt->m_num_phys);
2097 if (num_phys > MPTSAS_MAX_PHYS) {
2098 mptsas_log(mpt, CE_WARN, "Number of phys "
2099 "supported by HBA (%d) is more than max "
2100 "supported by driver (%d). Driver will "
2101 "not attach.", num_phys,
2102 MPTSAS_MAX_PHYS);
2103 rval = DDI_FAILURE;
2104 goto cleanup;
2105 }
2106 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2107 cpdi[i] = ddi_get32(page_accessp,
2108 &sasioupage0->PhyData[i].
2109 ControllerPhyDeviceInfo);
2110 port_flags = ddi_get8(page_accessp,
2111 &sasioupage0->PhyData[i].PortFlags);
2112
2113 mpt->m_phy_info[i].port_num =
2114 ddi_get8(page_accessp,
2115 &sasioupage0->PhyData[i].Port);
2116 mpt->m_phy_info[i].ctrl_devhdl =
2117 ddi_get16(page_accessp, &sasioupage0->
2118 PhyData[i].ControllerDevHandle);
2119 mpt->m_phy_info[i].attached_devhdl =
2120 ddi_get16(page_accessp, &sasioupage0->
2121 PhyData[i].AttachedDevHandle);
2122 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2123 mpt->m_phy_info[i].port_flags = port_flags;
2124
2125 if (port_flags & DISCOVERY_IN_PROGRESS) {
2126 retrypage0++;
2127 NDBG20(("Discovery in progress, can't "
2128 "verify IO unit config, then NO.%d"
2129 " times retry", retrypage0));
2130 break;
2131 } else {
2132 retrypage0 = 0;
2133 }
2134 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2135 /*
2136 * some PHY configuration described in
2137 * SAS IO Unit Page1
2138 */
2139 readpage1 = 1;
2140 }
2141 }
2142
2143 /*
2144 * retry 30 times if discovery is in process
2145 */
2146 if (retrypage0 && (retrypage0 < 30)) {
2147 drv_usecwait(1000 * 100);
2148 state = IOUC_READ_PAGE0;
2149 break;
2150 } else if (retrypage0 == 30) {
2151 mptsas_log(mpt, CE_WARN,
2152 "!Discovery in progress, can't "
2153 "verify IO unit config, then after"
2154 " 30 times retry, give up!");
2155 state = IOUC_DONE;
2156 rval = DDI_FAILURE;
2157 break;
2158 }
2159
2160 if (readpage1 == 0) {
2161 state = IOUC_DONE;
2162 rval = DDI_SUCCESS;
2163 break;
2164 }
2165
2166 state = IOUC_READ_PAGE1;
2167 break;
2168
2169 case IOUC_READ_PAGE1:
2170 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2171 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2172 goto cleanup;
2173 }
2174
2175 num_phys = ddi_get8(page_accessp,
2176 &sasioupage1->NumPhys);
2177 ASSERT(num_phys == mpt->m_num_phys);
2178 if (num_phys > MPTSAS_MAX_PHYS) {
2179 mptsas_log(mpt, CE_WARN, "Number of phys "
2180 "supported by HBA (%d) is more than max "
2181 "supported by driver (%d). Driver will "
2182 "not attach.", num_phys,
2183 MPTSAS_MAX_PHYS);
2184 rval = DDI_FAILURE;
2185 goto cleanup;
2186 }
2187 for (i = 0; i < num_phys; i++) {
2188 cpdi[i] = ddi_get32(page_accessp,
2189 &sasioupage1->PhyData[i].
2190 ControllerPhyDeviceInfo);
2191 port_flags = ddi_get8(page_accessp,
2192 &sasioupage1->PhyData[i].PortFlags);
2193 mpt->m_phy_info[i].port_num =
2194 ddi_get8(page_accessp,
2195 &sasioupage1->PhyData[i].Port);
2196 mpt->m_phy_info[i].port_flags = port_flags;
2197 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2198
2199 }
2200
2201 state = IOUC_DONE;
2202 rval = DDI_SUCCESS;
2203 break;
2204 }
2205 }
2206 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2207 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2208 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2209 rval = DDI_FAILURE;
2210 goto cleanup;
2211 }
2212 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2213 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2214 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2215 rval = DDI_FAILURE;
2216 goto cleanup;
2217 }
2218
2219 cleanup:
2220 if (free_recv)
2221 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2222 if (free_page)
2223 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2224 if (rval != DDI_SUCCESS) {
2225 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2226 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2227 }
2228 return (rval);
2229 }
2230
2231 /*
2232 * mptsas_get_manufacture_page5
2233 *
2234 * This function will retrieve the base WWID from the adapter. Since this
2235 * function is only called during the initialization process, use handshaking.
2236 */
2237 int
2238 mptsas_get_manufacture_page5(mptsas_t *mpt)
2239 {
2240 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2241 ddi_dma_cookie_t page_cookie;
2242 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2243 ddi_acc_handle_t recv_accessp, page_accessp;
2244 pMpi2ConfigReply_t configreply;
2245 caddr_t recv_memp, page_memp;
2246 int recv_numbytes;
2247 pMpi2ManufacturingPage5_t m5;
2248 uint32_t flagslength;
2249 int rval = DDI_SUCCESS;
2250 uint_t iocstatus;
2251 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2252
2253 MPTSAS_DISABLE_INTR(mpt);
2254
2255 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2256 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2257 rval = DDI_FAILURE;
2258 goto done;
2259 }
2260
2261 /*
2262 * dynamically create a customized dma attribute structure
2263 * that describes the MPT's config reply page request structure.
2264 */
2265 recv_dma_attrs = mpt->m_msg_dma_attr;
2266 recv_dma_attrs.dma_attr_sgllen = 1;
2267 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2268
2269 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2270 &recv_dma_handle, &recv_accessp, &recv_memp,
2271 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2272 rval = DDI_FAILURE;
2273 goto done;
2274 }
2275 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2276 free_recv = B_TRUE;
2277
2278 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2279 configreply = (pMpi2ConfigReply_t)recv_memp;
2280 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2281
2282 /*
2283 * get config reply message
2284 */
2285 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2286 recv_accessp)) {
2287 rval = DDI_FAILURE;
2288 goto done;
2289 }
2290
2291 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2292 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2293 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2294 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2295 goto done;
2296 }
2297
2298 /*
2299 * dynamically create a customized dma attribute structure
2300 * that describes the MPT's config page structure.
2301 */
2302 page_dma_attrs = mpt->m_msg_dma_attr;
2303 page_dma_attrs.dma_attr_sgllen = 1;
2304 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2305
2306 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2307 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2308 &page_cookie) == FALSE) {
2309 rval = DDI_FAILURE;
2310 goto done;
2311 }
2312 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2313 free_page = B_TRUE;
2314
2315 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2316 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2317
2318 /*
2319 * Give reply address to IOC to store config page in and send
2320 * config request out.
2321 */
2322
2323 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2324 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2325 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2326 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2327 MPI2_SGE_FLAGS_IOC_TO_HOST |
2328 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2329
2330 if (mptsas_send_config_request_msg(mpt,
2331 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2332 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2333 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2334 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2335 flagslength, page_cookie.dmac_address)) {
2336 rval = DDI_FAILURE;
2337 goto done;
2338 }
2339
2340 /*
2341 * get reply view handshake
2342 */
2343 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2344 recv_accessp)) {
2345 rval = DDI_FAILURE;
2346 goto done;
2347 }
2348
2349 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2350 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2351 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2352 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2353 goto done;
2354 }
2355
2356 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2357
2358 /*
2359 * Fusion-MPT stores fields in little-endian format. This is
2360 * why the low-order 32 bits are stored first.
2361 */
2362 mpt->un.sasaddr.m_base_wwid_lo =
2363 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2364 mpt->un.sasaddr.m_base_wwid_hi =
2365 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2366
2367 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2368 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2369 NDBG2(("%s%d: failed to create base-wwid property",
2370 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2371 }
2372
2373 /*
2374 * Set the number of PHYs present.
2375 */
2376 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2377
2378 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2379 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2380 NDBG2(("%s%d: failed to create num-phys property",
2381 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2382 }
2383
2384 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2385 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2386 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2387
2388 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2389 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2390 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2391 rval = DDI_FAILURE;
2392 goto done;
2393 }
2394 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2395 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2396 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2397 rval = DDI_FAILURE;
2398 }
2399 done:
2400 /*
2401 * free up memory
2402 */
2403 if (free_recv)
2404 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2405 if (free_page)
2406 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2407 MPTSAS_ENABLE_INTR(mpt);
2408
2409 return (rval);
2410 }
2411
2412 static int
2413 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2414 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2415 va_list ap)
2416 {
2417 #ifndef __lock_lint
2418 _NOTE(ARGUNUSED(ap))
2419 #endif
2420 pMpi2SasPhyPage0_t sasphypage;
2421 int rval = DDI_SUCCESS;
2422 uint16_t *owner_devhdl, *attached_devhdl;
2423 uint8_t *attached_phy_identify;
2424 uint32_t *attached_phy_info;
2425 uint8_t *programmed_link_rate;
2426 uint8_t *hw_link_rate;
2427 uint8_t *change_count;
2428 uint32_t *phy_info;
2429 uint8_t *negotiated_link_rate;
2430 uint32_t page_address;
2431
2432 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2433 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2434 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2435 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2436 iocstatus, iocloginfo);
2437 rval = DDI_FAILURE;
2438 return (rval);
2439 }
2440 page_address = va_arg(ap, uint32_t);
2441 /*
2442 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2443 * are no more pages. If everything is OK up to this point but the
2444 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2445 * signal that device traversal is complete.
2446 */
2447 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2448 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2449 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2450 mpt->m_done_traverse_smp = 1;
2451 }
2452 rval = DDI_FAILURE;
2453 return (rval);
2454 }
2455 owner_devhdl = va_arg(ap, uint16_t *);
2456 attached_devhdl = va_arg(ap, uint16_t *);
2457 attached_phy_identify = va_arg(ap, uint8_t *);
2458 attached_phy_info = va_arg(ap, uint32_t *);
2459 programmed_link_rate = va_arg(ap, uint8_t *);
2460 hw_link_rate = va_arg(ap, uint8_t *);
2461 change_count = va_arg(ap, uint8_t *);
2462 phy_info = va_arg(ap, uint32_t *);
2463 negotiated_link_rate = va_arg(ap, uint8_t *);
2464
2465 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2466
2467 *owner_devhdl =
2468 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2469 *attached_devhdl =
2470 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2471 *attached_phy_identify =
2472 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2473 *attached_phy_info =
2474 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2475 *programmed_link_rate =
2476 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2477 *hw_link_rate =
2478 ddi_get8(accessp, &sasphypage->HwLinkRate);
2479 *change_count =
2480 ddi_get8(accessp, &sasphypage->ChangeCount);
2481 *phy_info =
2482 ddi_get32(accessp, &sasphypage->PhyInfo);
2483 *negotiated_link_rate =
2484 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2485
2486 return (rval);
2487 }
2488
2489 /*
2490 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2491 * and SAS address.
2492 */
2493 int
2494 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2495 smhba_info_t *info)
2496 {
2497 int rval = DDI_SUCCESS;
2498
2499 ASSERT(mutex_owned(&mpt->m_mutex));
2500
2501 /*
2502 * Get the header and config page. reply contains the reply frame,
2503 * which holds status info for the request.
2504 */
2505 rval = mptsas_access_config_page(mpt,
2506 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2507 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2508 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2509 &info->attached_devhdl, &info->attached_phy_identify,
2510 &info->attached_phy_info, &info->programmed_link_rate,
2511 &info->hw_link_rate, &info->change_count,
2512 &info->phy_info, &info->negotiated_link_rate);
2513
2514 return (rval);
2515 }
2516
2517 static int
2518 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2519 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2520 va_list ap)
2521 {
2522 #ifndef __lock_lint
2523 _NOTE(ARGUNUSED(ap))
2524 #endif
2525 pMpi2SasPhyPage1_t sasphypage;
2526 int rval = DDI_SUCCESS;
2527
2528 uint32_t *invalid_dword_count;
2529 uint32_t *running_disparity_error_count;
2530 uint32_t *loss_of_dword_sync_count;
2531 uint32_t *phy_reset_problem_count;
2532 uint32_t page_address;
2533
2534 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2535 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2536 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2537 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2538 iocstatus, iocloginfo);
2539 rval = DDI_FAILURE;
2540 return (rval);
2541 }
2542 page_address = va_arg(ap, uint32_t);
2543 /*
2544 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2545 * are no more pages. If everything is OK up to this point but the
2546 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2547 * signal that device traversal is complete.
2548 */
2549 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2550 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2551 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2552 mpt->m_done_traverse_smp = 1;
2553 }
2554 rval = DDI_FAILURE;
2555 return (rval);
2556 }
2557
2558 invalid_dword_count = va_arg(ap, uint32_t *);
2559 running_disparity_error_count = va_arg(ap, uint32_t *);
2560 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2561 phy_reset_problem_count = va_arg(ap, uint32_t *);
2562
2563 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2564
2565 *invalid_dword_count =
2566 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2567 *running_disparity_error_count =
2568 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2569 *loss_of_dword_sync_count =
2570 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2571 *phy_reset_problem_count =
2572 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2573
2574 return (rval);
2575 }
2576
2577 /*
2578 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2579 * and SAS address.
2580 */
2581 int
2582 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2583 smhba_info_t *info)
2584 {
2585 int rval = DDI_SUCCESS;
2586
2587 ASSERT(mutex_owned(&mpt->m_mutex));
2588
2589 /*
2590 * Get the header and config page. reply contains the reply frame,
2591 * which holds status info for the request.
2592 */
2593 rval = mptsas_access_config_page(mpt,
2594 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2595 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2596 mptsas_sasphypage_1_cb, page_address,
2597 &info->invalid_dword_count,
2598 &info->running_disparity_error_count,
2599 &info->loss_of_dword_sync_count,
2600 &info->phy_reset_problem_count);
2601
2602 return (rval);
2603 }
2604 /*
2605 * mptsas_get_manufacture_page0
2606 *
2607 * This function will retrieve the base
2608 * Chip name, Board Name,Board Trace number from the adapter.
2609 * Since this function is only called during the
2610 * initialization process, use handshaking.
2611 */
2612 int
2613 mptsas_get_manufacture_page0(mptsas_t *mpt)
2614 {
2615 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2616 ddi_dma_cookie_t page_cookie;
2617 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2618 ddi_acc_handle_t recv_accessp, page_accessp;
2619 pMpi2ConfigReply_t configreply;
2620 caddr_t recv_memp, page_memp;
2621 int recv_numbytes;
2622 pMpi2ManufacturingPage0_t m0;
2623 uint32_t flagslength;
2624 int rval = DDI_SUCCESS;
2625 uint_t iocstatus;
2626 uint8_t i = 0;
2627 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2628
2629 MPTSAS_DISABLE_INTR(mpt);
2630
2631 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2632 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2633 rval = DDI_FAILURE;
2634 goto done;
2635 }
2636
2637 /*
2638 * dynamically create a customized dma attribute structure
2639 * that describes the MPT's config reply page request structure.
2640 */
2641 recv_dma_attrs = mpt->m_msg_dma_attr;
2642 recv_dma_attrs.dma_attr_sgllen = 1;
2643 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2644
2645 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2646 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2647 NULL) == FALSE) {
2648 rval = DDI_FAILURE;
2649 goto done;
2650 }
2651 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2652 free_recv = B_TRUE;
2653
2654 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2655 configreply = (pMpi2ConfigReply_t)recv_memp;
2656 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2657
2658 /*
2659 * get config reply message
2660 */
2661 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2662 recv_accessp)) {
2663 rval = DDI_FAILURE;
2664 goto done;
2665 }
2666
2667 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2668 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2669 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2670 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2671 goto done;
2672 }
2673
2674 /*
2675 * dynamically create a customized dma attribute structure
2676 * that describes the MPT's config page structure.
2677 */
2678 page_dma_attrs = mpt->m_msg_dma_attr;
2679 page_dma_attrs.dma_attr_sgllen = 1;
2680 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2681
2682 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2683 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2684 &page_cookie) == FALSE) {
2685 rval = DDI_FAILURE;
2686 goto done;
2687 }
2688 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2689 free_page = B_TRUE;
2690
2691 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2692 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2693
2694 /*
2695 * Give reply address to IOC to store config page in and send
2696 * config request out.
2697 */
2698
2699 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2700 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2701 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2702 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2703 MPI2_SGE_FLAGS_IOC_TO_HOST |
2704 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2705
2706 if (mptsas_send_config_request_msg(mpt,
2707 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2708 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2709 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2710 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2711 flagslength, page_cookie.dmac_address)) {
2712 rval = DDI_FAILURE;
2713 goto done;
2714 }
2715
2716 /*
2717 * get reply view handshake
2718 */
2719 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2720 recv_accessp)) {
2721 rval = DDI_FAILURE;
2722 goto done;
2723 }
2724
2725 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2726 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2727 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2728 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2729 goto done;
2730 }
2731
2732 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2733
2734 /*
2735 * Fusion-MPT stores fields in little-endian format. This is
2736 * why the low-order 32 bits are stored first.
2737 */
2738
2739 for (i = 0; i < 16; i++) {
2740 mpt->m_MANU_page0.ChipName[i] =
2741 ddi_get8(page_accessp,
2742 (uint8_t *)(void *)&m0->ChipName[i]);
2743 }
2744
2745 for (i = 0; i < 8; i++) {
2746 mpt->m_MANU_page0.ChipRevision[i] =
2747 ddi_get8(page_accessp,
2748 (uint8_t *)(void *)&m0->ChipRevision[i]);
2749 }
2750
2751 for (i = 0; i < 16; i++) {
2752 mpt->m_MANU_page0.BoardName[i] =
2753 ddi_get8(page_accessp,
2754 (uint8_t *)(void *)&m0->BoardName[i]);
2755 }
2756
2757 for (i = 0; i < 16; i++) {
2758 mpt->m_MANU_page0.BoardAssembly[i] =
2759 ddi_get8(page_accessp,
2760 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2761 }
2762
2763 for (i = 0; i < 16; i++) {
2764 mpt->m_MANU_page0.BoardTracerNumber[i] =
2765 ddi_get8(page_accessp,
2766 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2767 }
2768
2769 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2770 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2771 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2772 rval = DDI_FAILURE;
2773 goto done;
2774 }
2775 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2776 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2777 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2778 rval = DDI_FAILURE;
2779 }
2780 done:
2781 /*
2782 * free up memory
2783 */
2784 if (free_recv)
2785 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2786 if (free_page)
2787 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2788 MPTSAS_ENABLE_INTR(mpt);
2789
2790 return (rval);
2791 }