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 ioc_cmd->m_event_linkp = NULL;
1048 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1049 *cmd = &(ioc_cmd->m_event_cmd);
1050 *pkt = &(ioc_cmd->m_event_pkt);
1051
1052 return (DDI_SUCCESS);
1053 }
1054
1055 void
1056 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1057 {
1058 m_event_struct_t *ioc_cmd = NULL;
1059
1060 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1061 if (ioc_cmd == NULL) {
1062 return;
1063 }
1064
1065 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1066 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1067 ioc_cmd = NULL;
1068 }
1069
1070 /*
1071 * NOTE: We should be able to queue TM requests in the controller to make this
1072 * a lot faster. If resetting all targets, for example, we can load the hi
1073 * priority queue with its limit and the controller will reply as they are
1074 * completed. This way, we don't have to poll for one reply at a time.
1075 * Think about enhancing this later.
1076 */
1077 int
1078 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1079 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1080 {
1081 /*
1082 * In order to avoid allocating variables on the stack,
1083 * we make use of the pre-existing mptsas_cmd_t and
1084 * scsi_pkt which are included in the mptsas_t which
1085 * is passed to this routine.
1086 */
1087
1088 pMpi2SCSITaskManagementRequest_t task;
1089 int rval = FALSE;
1090 mptsas_cmd_t *cmd;
1091 struct scsi_pkt *pkt;
1092 mptsas_slots_t *slots = mpt->m_active;
1093 uint32_t request_desc_low, i;
1094 pMPI2DefaultReply_t reply_msg;
1095
1096 /*
1097 * Can't start another task management routine.
1098 */
1099 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1100 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1101 " command at a time\n");
1102 return (FALSE);
1103 }
1104
1105 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1106 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1107
1108 bzero((caddr_t)cmd, sizeof (*cmd));
1109 bzero((caddr_t)pkt, scsi_pkt_size());
1110
1111 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1112 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1113 pkt->pkt_ha_private = (opaque_t)cmd;
1114 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1115 pkt->pkt_time = 60;
1116 pkt->pkt_address.a_target = dev_handle;
1117 pkt->pkt_address.a_lun = (uchar_t)lun;
1118 cmd->cmd_pkt = pkt;
1119 cmd->cmd_scblen = 1;
1120 cmd->cmd_flags = CFLAG_TM_CMD;
1121 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1122
1123 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1124
1125 /*
1126 * Store the TM message in memory location corresponding to the TM slot
1127 * number.
1128 */
1129 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1130 (mpt->m_req_frame_size * cmd->cmd_slot));
1131 bzero(task, mpt->m_req_frame_size);
1132
1133 /*
1134 * form message for requested task
1135 */
1136 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1137 MPI2_FUNCTION_SCSI_TASK_MGMT);
1138
1139 /*
1140 * Set the task type
1141 */
1142 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1143
1144 /*
1145 * Send TM request using High Priority Queue.
1146 */
1147 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1148 DDI_DMA_SYNC_FORDEV);
1149 request_desc_low = (cmd->cmd_slot << 16) +
1150 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1151 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1152 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1153
1154 if (pkt->pkt_reason == CMD_INCOMPLETE)
1155 rval = FALSE;
1156
1157 /*
1158 * If a reply frame was used and there is a reply buffer to copy the
1159 * reply data into, copy it. If this fails, log a message, but don't
1160 * fail the TM request.
1161 */
1162 if (cmd->cmd_rfm && reply) {
1163 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1164 DDI_DMA_SYNC_FORCPU);
1165 reply_msg = (pMPI2DefaultReply_t)
1166 (mpt->m_reply_frame + (cmd->cmd_rfm -
1167 mpt->m_reply_frame_dma_addr));
1168 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1169 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1170 }
1171 mutex_exit(&mpt->m_mutex);
1172 for (i = 0; i < reply_size; i++) {
1173 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1174 mode)) {
1175 mptsas_log(mpt, CE_WARN, "failed to copy out "
1176 "reply data for TM request");
1177 break;
1178 }
1179 }
1180 mutex_enter(&mpt->m_mutex);
1181 }
1182
1183 /*
1184 * clear the TM slot before returning
1185 */
1186 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1187
1188 /*
1189 * If we lost our task management command
1190 * we need to reset the ioc
1191 */
1192 if (rval == FALSE) {
1193 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1194 "try to reset ioc to recovery!");
1195 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1196 if (mptsas_restart_ioc(mpt)) {
1197 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1198 rval = FAILED;
1199 }
1200 }
1201
1202 return (rval);
1203 }
1204
1205 /*
1206 * Complete firmware download frame for v2.0 cards.
1207 */
1208 static void
1209 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1210 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1211 ddi_dma_cookie_t flsh_cookie)
1212 {
1213 pMpi2FWDownloadTCSGE_t tcsge;
1214 pMpi2SGESimple64_t sge;
1215 uint32_t flagslength;
1216
1217 ddi_put8(acc_hdl, &fwdownload->Function,
1218 MPI2_FUNCTION_FW_DOWNLOAD);
1219 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1220 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1221 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1222 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1223
1224 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1225 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1226 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1227 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1228 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1229 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1230
1231 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1232 flagslength = size;
1233 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1234 MPI2_SGE_FLAGS_END_OF_BUFFER |
1235 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1236 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1237 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1238 MPI2_SGE_FLAGS_HOST_TO_IOC |
1239 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1240 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1241 ddi_put32(acc_hdl, &sge->Address.Low,
1242 flsh_cookie.dmac_address);
1243 ddi_put32(acc_hdl, &sge->Address.High,
1244 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1245 }
1246
1247 /*
1248 * Complete firmware download frame for v2.5 cards.
1249 */
1250 static void
1251 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1252 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1253 ddi_dma_cookie_t flsh_cookie)
1254 {
1255 pMpi2IeeeSgeSimple64_t sge;
1256 uint8_t flags;
1257
1258 ddi_put8(acc_hdl, &fwdownload->Function,
1259 MPI2_FUNCTION_FW_DOWNLOAD);
1260 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1261 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1262 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1263 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1264
1265 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1266 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1267
1268 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1269 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1270 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1271 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1272 ddi_put8(acc_hdl, &sge->Flags, flags);
1273 ddi_put32(acc_hdl, &sge->Length, size);
1274 ddi_put32(acc_hdl, &sge->Address.Low,
1275 flsh_cookie.dmac_address);
1276 ddi_put32(acc_hdl, &sge->Address.High,
1277 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1278 }
1279
1280 static int mptsas_enable_mpi25_flashupdate = 0;
1281
1282 int
1283 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1284 uint8_t type, int mode)
1285 {
1286
1287 /*
1288 * In order to avoid allocating variables on the stack,
1289 * we make use of the pre-existing mptsas_cmd_t and
1290 * scsi_pkt which are included in the mptsas_t which
1291 * is passed to this routine.
1292 */
1293
1294 ddi_dma_attr_t flsh_dma_attrs;
1295 ddi_dma_cookie_t flsh_cookie;
1296 ddi_dma_handle_t flsh_dma_handle;
1297 ddi_acc_handle_t flsh_accessp;
1298 caddr_t memp, flsh_memp;
1299 mptsas_cmd_t *cmd;
1300 struct scsi_pkt *pkt;
1301 int i;
1302 int rvalue = 0;
1303 uint32_t request_desc_low;
1304
1305 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1306 /*
1307 * The code is there but not tested yet.
1308 * User has to know there are risks here.
1309 */
1310 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1311 "Updating firmware through MPI 2.5 has not been "
1312 "tested yet!\n"
1313 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1314 return (-1);
1315 } /* Otherwise, you pay your money and you take your chances. */
1316
1317 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1318 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1319 "failed. event ack command pool is full\n");
1320 return (rvalue);
1321 }
1322
1323 bzero((caddr_t)cmd, sizeof (*cmd));
1324 bzero((caddr_t)pkt, scsi_pkt_size());
1325 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1326
1327 /*
1328 * dynamically create a customized dma attribute structure
1329 * that describes the flash file.
1330 */
1331 flsh_dma_attrs = mpt->m_msg_dma_attr;
1332 flsh_dma_attrs.dma_attr_sgllen = 1;
1333
1334 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1335 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1336 mptsas_log(mpt, CE_WARN,
1337 "(unable to allocate dma resource.");
1338 mptsas_return_to_pool(mpt, cmd);
1339 return (-1);
1340 }
1341
1342 bzero(flsh_memp, size);
1343
1344 for (i = 0; i < size; i++) {
1345 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1346 }
1347 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1348
1349 /*
1350 * form a cmd/pkt to store the fw download message
1351 */
1352 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1353 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1354 pkt->pkt_ha_private = (opaque_t)cmd;
1355 pkt->pkt_flags = FLAG_HEAD;
1356 pkt->pkt_time = 60;
1357 cmd->cmd_pkt = pkt;
1358 cmd->cmd_scblen = 1;
1359 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1360
1361 /*
1362 * Save the command in a slot
1363 */
1364 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1365 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1366 mptsas_return_to_pool(mpt, cmd);
1367 return (-1);
1368 }
1369
1370 /*
1371 * Fill in fw download message
1372 */
1373 ASSERT(cmd->cmd_slot != 0);
1374 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1375 bzero(memp, mpt->m_req_frame_size);
1376
1377 if (mpt->m_MPI25)
1378 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1379 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1380 else
1381 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1382 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1383
1384 /*
1385 * Start command
1386 */
1387 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1388 DDI_DMA_SYNC_FORDEV);
1389 request_desc_low = (cmd->cmd_slot << 16) +
1390 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1391 cmd->cmd_rfm = NULL;
1392 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1393
1394 rvalue = 0;
1395 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1396 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1397 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1398 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1399 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1400 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1401 }
1402 rvalue = -1;
1403 }
1404 mptsas_remove_cmd(mpt, cmd);
1405 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1406
1407 return (rvalue);
1408 }
1409
1410 static int
1411 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1412 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1413 va_list ap)
1414 {
1415 #ifndef __lock_lint
1416 _NOTE(ARGUNUSED(ap))
1417 #endif
1418 pMpi2SasDevicePage0_t sasdevpage;
1419 int rval = DDI_SUCCESS, i;
1420 uint8_t *sas_addr = NULL;
1421 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1422 uint16_t *devhdl, *bay_num, *enclosure;
1423 uint64_t *sas_wwn;
1424 uint32_t *dev_info;
1425 uint8_t *physport, *phynum;
1426 uint16_t *pdevhdl, *io_flags;
1427 uint32_t page_address;
1428
1429 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1430 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1431 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1432 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1433 iocstatus, iocloginfo);
1434 rval = DDI_FAILURE;
1435 return (rval);
1436 }
1437 page_address = va_arg(ap, uint32_t);
1438 /*
1439 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1440 * are no more pages. If everything is OK up to this point but the
1441 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1442 * signal that device traversal is complete.
1443 */
1444 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1445 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1446 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1447 mpt->m_done_traverse_dev = 1;
1448 }
1449 rval = DDI_FAILURE;
1450 return (rval);
1451 }
1452 devhdl = va_arg(ap, uint16_t *);
1453 sas_wwn = va_arg(ap, uint64_t *);
1454 dev_info = va_arg(ap, uint32_t *);
1455 physport = va_arg(ap, uint8_t *);
1456 phynum = va_arg(ap, uint8_t *);
1457 pdevhdl = va_arg(ap, uint16_t *);
1458 bay_num = va_arg(ap, uint16_t *);
1459 enclosure = va_arg(ap, uint16_t *);
1460 io_flags = va_arg(ap, uint16_t *);
1461
1462 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1463
1464 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1465 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1466 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1467 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1468 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1469 }
1470 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1471 *sas_wwn = LE_64(*sas_wwn);
1472 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1473 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1474 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1475 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1476 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1477 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1478
1479 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1480 /*
1481 * Leave a messages about FP cabability in the log.
1482 */
1483 mptsas_log(mpt, CE_CONT,
1484 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1485 (*io_flags &
1486 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1487 " and Enabled":" but Disabled");
1488 }
1489
1490 return (rval);
1491 }
1492
1493 /*
1494 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1495 * info and SAS address.
1496 */
1497 int
1498 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1499 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1500 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1501 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1502 {
1503 int rval = DDI_SUCCESS;
1504
1505 ASSERT(mutex_owned(&mpt->m_mutex));
1506
1507 /*
1508 * Get the header and config page. reply contains the reply frame,
1509 * which holds status info for the request.
1510 */
1511 rval = mptsas_access_config_page(mpt,
1512 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1513 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1514 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1515 dev_info, physport, phynum, pdev_handle,
1516 bay_num, enclosure, io_flags);
1517
1518 return (rval);
1519 }
1520
1521 static int
1522 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1523 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1524 va_list ap)
1525 {
1526 #ifndef __lock_lint
1527 _NOTE(ARGUNUSED(ap))
1528 #endif
1529 pMpi2ExpanderPage0_t expddevpage;
1530 int rval = DDI_SUCCESS, i;
1531 uint8_t *sas_addr = NULL;
1532 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1533 uint16_t *devhdl;
1534 uint64_t *sas_wwn;
1535 uint8_t physport;
1536 mptsas_phymask_t *phymask;
1537 uint16_t *pdevhdl;
1538 uint32_t page_address;
1539
1540 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1541 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1542 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1543 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1544 iocstatus, iocloginfo);
1545 rval = DDI_FAILURE;
1546 return (rval);
1547 }
1548 page_address = va_arg(ap, uint32_t);
1549 /*
1550 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1551 * are no more pages. If everything is OK up to this point but the
1552 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1553 * signal that device traversal is complete.
1554 */
1555 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1556 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1557 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1558 mpt->m_done_traverse_smp = 1;
1559 }
1560 rval = DDI_FAILURE;
1561 return (rval);
1562 }
1563 devhdl = va_arg(ap, uint16_t *);
1564 sas_wwn = va_arg(ap, uint64_t *);
1565 phymask = va_arg(ap, mptsas_phymask_t *);
1566 pdevhdl = va_arg(ap, uint16_t *);
1567
1568 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1569
1570 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1571 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1572 *phymask = mptsas_physport_to_phymask(mpt, physport);
1573 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1574 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1575 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1576 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1577 }
1578 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1579 *sas_wwn = LE_64(*sas_wwn);
1580
1581 return (rval);
1582 }
1583
1584 /*
1585 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1586 * and SAS address.
1587 */
1588 int
1589 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1590 mptsas_smp_t *info)
1591 {
1592 int rval = DDI_SUCCESS;
1593
1594 ASSERT(mutex_owned(&mpt->m_mutex));
1595
1596 /*
1597 * Get the header and config page. reply contains the reply frame,
1598 * which holds status info for the request.
1599 */
1600 rval = mptsas_access_config_page(mpt,
1601 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1602 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1603 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1604 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1605
1606 return (rval);
1607 }
1608
1609 static int
1610 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1611 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1612 va_list ap)
1613 {
1614 #ifndef __lock_lint
1615 _NOTE(ARGUNUSED(ap))
1616 #endif
1617 int rval = DDI_SUCCESS, i;
1618 uint8_t *sas_addr = NULL;
1619 uint64_t *sas_wwn;
1620 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1621 uint8_t *portwidth;
1622 pMpi2SasPortPage0_t sasportpage;
1623
1624 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1625 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1626 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1627 iocstatus, iocloginfo);
1628 rval = DDI_FAILURE;
1629 return (rval);
1630 }
1631 sas_wwn = va_arg(ap, uint64_t *);
1632 portwidth = va_arg(ap, uint8_t *);
1633
1634 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1635 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1636 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1637 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1638 }
1639 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1640 *sas_wwn = LE_64(*sas_wwn);
1641 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1642 return (rval);
1643 }
1644
1645 /*
1646 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1647 * and port width.
1648 */
1649 int
1650 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1651 uint64_t *sas_wwn, uint8_t *portwidth)
1652 {
1653 int rval = DDI_SUCCESS;
1654
1655 ASSERT(mutex_owned(&mpt->m_mutex));
1656
1657 /*
1658 * Get the header and config page. reply contains the reply frame,
1659 * which holds status info for the request.
1660 */
1661 rval = mptsas_access_config_page(mpt,
1662 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1663 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1664 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1665
1666 return (rval);
1667 }
1668
1669 static int
1670 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1671 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1672 va_list ap)
1673 {
1674 #ifndef __lock_lint
1675 _NOTE(ARGUNUSED(ap))
1676 #endif
1677 int rval = DDI_SUCCESS;
1678 pMpi2SasIOUnitPage0_t sasioupage0;
1679 int i, num_phys;
1680 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1681 uint8_t port_flags;
1682
1683 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1684 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1685 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1686 iocstatus, iocloginfo);
1687 rval = DDI_FAILURE;
1688 return (rval);
1689 }
1690 readpage1 = va_arg(ap, uint32_t *);
1691 retrypage0 = va_arg(ap, uint32_t *);
1692
1693 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1694
1695 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1696 /*
1697 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1698 * was initially set. This should never change throughout the life of
1699 * the driver.
1700 */
1701 ASSERT(num_phys == mpt->m_num_phys);
1702 for (i = 0; i < num_phys; i++) {
1703 cpdi[i] = ddi_get32(accessp,
1704 &sasioupage0->PhyData[i].
1705 ControllerPhyDeviceInfo);
1706 port_flags = ddi_get8(accessp,
1707 &sasioupage0->PhyData[i].PortFlags);
1708 mpt->m_phy_info[i].port_num =
1709 ddi_get8(accessp,
1710 &sasioupage0->PhyData[i].Port);
1711 mpt->m_phy_info[i].ctrl_devhdl =
1712 ddi_get16(accessp, &sasioupage0->
1713 PhyData[i].ControllerDevHandle);
1714 mpt->m_phy_info[i].attached_devhdl =
1715 ddi_get16(accessp, &sasioupage0->
1716 PhyData[i].AttachedDevHandle);
1717 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1718 mpt->m_phy_info[i].port_flags = port_flags;
1719
1720 if (port_flags & DISCOVERY_IN_PROGRESS) {
1721 *retrypage0 = *retrypage0 + 1;
1722 break;
1723 } else {
1724 *retrypage0 = 0;
1725 }
1726 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1727 /*
1728 * some PHY configuration described in
1729 * SAS IO Unit Page1
1730 */
1731 *readpage1 = 1;
1732 }
1733 }
1734
1735 return (rval);
1736 }
1737
1738 static int
1739 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1740 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1741 va_list ap)
1742 {
1743 #ifndef __lock_lint
1744 _NOTE(ARGUNUSED(ap))
1745 #endif
1746 int rval = DDI_SUCCESS;
1747 pMpi2SasIOUnitPage1_t sasioupage1;
1748 int i, num_phys;
1749 uint32_t cpdi[MPTSAS_MAX_PHYS];
1750 uint8_t port_flags;
1751
1752 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1753 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1754 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1755 iocstatus, iocloginfo);
1756 rval = DDI_FAILURE;
1757 return (rval);
1758 }
1759
1760 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1761 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1762 /*
1763 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1764 * was initially set. This should never change throughout the life of
1765 * the driver.
1766 */
1767 ASSERT(num_phys == mpt->m_num_phys);
1768 for (i = 0; i < num_phys; i++) {
1769 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1770 ControllerPhyDeviceInfo);
1771 port_flags = ddi_get8(accessp,
1772 &sasioupage1->PhyData[i].PortFlags);
1773 mpt->m_phy_info[i].port_num =
1774 ddi_get8(accessp,
1775 &sasioupage1->PhyData[i].Port);
1776 mpt->m_phy_info[i].port_flags = port_flags;
1777 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1778 }
1779 return (rval);
1780 }
1781
1782 /*
1783 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1784 * page1 to update the PHY information. This is the message passing method of
1785 * this function which should be called except during initialization.
1786 */
1787 int
1788 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1789 {
1790 int rval = DDI_SUCCESS, state;
1791 uint32_t readpage1 = 0, retrypage0 = 0;
1792
1793 ASSERT(mutex_owned(&mpt->m_mutex));
1794
1795 /*
1796 * Now we cycle through the state machine. Here's what happens:
1797 * 1. Read IO unit page 0 and set phy information
1798 * 2. See if Read IO unit page1 is needed because of port configuration
1799 * 3. Read IO unit page 1 and update phy information.
1800 */
1801 state = IOUC_READ_PAGE0;
1802 while (state != IOUC_DONE) {
1803 if (state == IOUC_READ_PAGE0) {
1804 rval = mptsas_access_config_page(mpt,
1805 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1806 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1807 mptsas_sasiou_page_0_cb, &readpage1,
1808 &retrypage0);
1809 } else if (state == IOUC_READ_PAGE1) {
1810 rval = mptsas_access_config_page(mpt,
1811 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1812 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1813 mptsas_sasiou_page_1_cb);
1814 }
1815
1816 if (rval == DDI_SUCCESS) {
1817 switch (state) {
1818 case IOUC_READ_PAGE0:
1819 /*
1820 * retry 30 times if discovery is in process
1821 */
1822 if (retrypage0 && (retrypage0 < 30)) {
1823 drv_usecwait(1000 * 100);
1824 state = IOUC_READ_PAGE0;
1825 break;
1826 } else if (retrypage0 == 30) {
1827 mptsas_log(mpt, CE_WARN,
1828 "!Discovery in progress, can't "
1829 "verify IO unit config, then "
1830 "after 30 times retry, give "
1831 "up!");
1832 state = IOUC_DONE;
1833 rval = DDI_FAILURE;
1834 break;
1835 }
1836
1837 if (readpage1 == 0) {
1838 state = IOUC_DONE;
1839 rval = DDI_SUCCESS;
1840 break;
1841 }
1842
1843 state = IOUC_READ_PAGE1;
1844 break;
1845
1846 case IOUC_READ_PAGE1:
1847 state = IOUC_DONE;
1848 rval = DDI_SUCCESS;
1849 break;
1850 }
1851 } else {
1852 return (rval);
1853 }
1854 }
1855
1856 return (rval);
1857 }
1858
1859 static int
1860 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1861 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1862 va_list ap)
1863 {
1864 #ifndef __lock_lint
1865 _NOTE(ARGUNUSED(ap))
1866 #endif
1867 pMpi2BiosPage3_t sasbiospage;
1868 int rval = DDI_SUCCESS;
1869 uint32_t *bios_version;
1870
1871 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1872 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1873 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1874 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1875 rval = DDI_FAILURE;
1876 return (rval);
1877 }
1878 bios_version = va_arg(ap, uint32_t *);
1879 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1880 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1881
1882 return (rval);
1883 }
1884
1885 /*
1886 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1887 * other information in this page is not needed, just ignore it.
1888 */
1889 int
1890 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1891 {
1892 int rval = DDI_SUCCESS;
1893
1894 ASSERT(mutex_owned(&mpt->m_mutex));
1895
1896 /*
1897 * Get the header and config page. reply contains the reply frame,
1898 * which holds status info for the request.
1899 */
1900 rval = mptsas_access_config_page(mpt,
1901 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1902 0, mptsas_biospage_3_cb, bios_version);
1903
1904 return (rval);
1905 }
1906
1907 /*
1908 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1909 * page1 to update the PHY information. This is the handshaking version of
1910 * this function, which should be called during initialization only.
1911 */
1912 int
1913 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1914 {
1915 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1916 ddi_dma_cookie_t page_cookie;
1917 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1918 ddi_acc_handle_t recv_accessp, page_accessp;
1919 pMpi2ConfigReply_t configreply;
1920 pMpi2SasIOUnitPage0_t sasioupage0;
1921 pMpi2SasIOUnitPage1_t sasioupage1;
1922 int recv_numbytes;
1923 caddr_t recv_memp, page_memp;
1924 int i, num_phys, start_phy = 0;
1925 int page0_size =
1926 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1927 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1928 int page1_size =
1929 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1930 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1931 uint32_t flags_length;
1932 uint32_t cpdi[MPTSAS_MAX_PHYS];
1933 uint32_t readpage1 = 0, retrypage0 = 0;
1934 uint16_t iocstatus;
1935 uint8_t port_flags, page_number, action;
1936 uint32_t reply_size = 256; /* Big enough for any page */
1937 uint_t state;
1938 int rval = DDI_FAILURE;
1939 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1940
1941 /*
1942 * Initialize our "state machine". This is a bit convoluted,
1943 * but it keeps us from having to do the ddi allocations numerous
1944 * times.
1945 */
1946
1947 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1948 ASSERT(mutex_owned(&mpt->m_mutex));
1949 state = IOUC_READ_PAGE0;
1950
1951 /*
1952 * dynamically create a customized dma attribute structure
1953 * that describes mpt's config reply page request structure.
1954 */
1955 recv_dma_attrs = mpt->m_msg_dma_attr;
1956 recv_dma_attrs.dma_attr_sgllen = 1;
1957 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1958
1959 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1960 &recv_dma_handle, &recv_accessp, &recv_memp,
1961 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1962 mptsas_log(mpt, CE_WARN,
1963 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1964 goto cleanup;
1965 }
1966 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1967 free_recv = B_TRUE;
1968
1969 page_dma_attrs = mpt->m_msg_dma_attr;
1970 page_dma_attrs.dma_attr_sgllen = 1;
1971 page_dma_attrs.dma_attr_granular = reply_size;
1972
1973 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1974 &page_dma_handle, &page_accessp, &page_memp,
1975 reply_size, &page_cookie) == FALSE) {
1976 mptsas_log(mpt, CE_WARN,
1977 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1978 goto cleanup;
1979 }
1980 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1981 free_page = B_TRUE;
1982
1983 /*
1984 * Now we cycle through the state machine. Here's what happens:
1985 * 1. Read IO unit page 0 and set phy information
1986 * 2. See if Read IO unit page1 is needed because of port configuration
1987 * 3. Read IO unit page 1 and update phy information.
1988 */
1989
1990 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1991 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1992
1993 while (state != IOUC_DONE) {
1994 switch (state) {
1995 case IOUC_READ_PAGE0:
1996 page_number = 0;
1997 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1998 flags_length = (uint32_t)page0_size;
1999 flags_length |= ((uint32_t)(
2000 MPI2_SGE_FLAGS_LAST_ELEMENT |
2001 MPI2_SGE_FLAGS_END_OF_BUFFER |
2002 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2003 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2004 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2005 MPI2_SGE_FLAGS_IOC_TO_HOST |
2006 MPI2_SGE_FLAGS_END_OF_LIST) <<
2007 MPI2_SGE_FLAGS_SHIFT);
2008
2009 break;
2010
2011 case IOUC_READ_PAGE1:
2012 page_number = 1;
2013 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2014 flags_length = (uint32_t)page1_size;
2015 flags_length |= ((uint32_t)(
2016 MPI2_SGE_FLAGS_LAST_ELEMENT |
2017 MPI2_SGE_FLAGS_END_OF_BUFFER |
2018 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2019 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2020 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2021 MPI2_SGE_FLAGS_IOC_TO_HOST |
2022 MPI2_SGE_FLAGS_END_OF_LIST) <<
2023 MPI2_SGE_FLAGS_SHIFT);
2024
2025 break;
2026 default:
2027 break;
2028 }
2029
2030 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2031 configreply = (pMpi2ConfigReply_t)recv_memp;
2032 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2033
2034 if (mptsas_send_extended_config_request_msg(mpt,
2035 MPI2_CONFIG_ACTION_PAGE_HEADER,
2036 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2037 0, page_number, 0, 0, 0, 0)) {
2038 goto cleanup;
2039 }
2040
2041 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2042 recv_accessp)) {
2043 goto cleanup;
2044 }
2045
2046 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2047 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2048
2049 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2050 mptsas_log(mpt, CE_WARN,
2051 "mptsas_get_sas_io_unit_page_hndshk: read page "
2052 "header iocstatus = 0x%x", iocstatus);
2053 goto cleanup;
2054 }
2055
2056 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2057 bzero(page_memp, reply_size);
2058 }
2059
2060 if (mptsas_send_extended_config_request_msg(mpt, action,
2061 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2062 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2063 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2064 flags_length, page_cookie.dmac_address)) {
2065 goto cleanup;
2066 }
2067
2068 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2069 recv_accessp)) {
2070 goto cleanup;
2071 }
2072
2073 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2074 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2075
2076 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2077 mptsas_log(mpt, CE_WARN,
2078 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2079 "config failed for action %d, iocstatus = 0x%x",
2080 action, iocstatus);
2081 goto cleanup;
2082 }
2083
2084 switch (state) {
2085 case IOUC_READ_PAGE0:
2086 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2087 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2088 goto cleanup;
2089 }
2090
2091 num_phys = ddi_get8(page_accessp,
2092 &sasioupage0->NumPhys);
2093 ASSERT(num_phys == mpt->m_num_phys);
2094 if (num_phys > MPTSAS_MAX_PHYS) {
2095 mptsas_log(mpt, CE_WARN, "Number of phys "
2096 "supported by HBA (%d) is more than max "
2097 "supported by driver (%d). Driver will "
2098 "not attach.", num_phys,
2099 MPTSAS_MAX_PHYS);
2100 rval = DDI_FAILURE;
2101 goto cleanup;
2102 }
2103 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2104 cpdi[i] = ddi_get32(page_accessp,
2105 &sasioupage0->PhyData[i].
2106 ControllerPhyDeviceInfo);
2107 port_flags = ddi_get8(page_accessp,
2108 &sasioupage0->PhyData[i].PortFlags);
2109
2110 mpt->m_phy_info[i].port_num =
2111 ddi_get8(page_accessp,
2112 &sasioupage0->PhyData[i].Port);
2113 mpt->m_phy_info[i].ctrl_devhdl =
2114 ddi_get16(page_accessp, &sasioupage0->
2115 PhyData[i].ControllerDevHandle);
2116 mpt->m_phy_info[i].attached_devhdl =
2117 ddi_get16(page_accessp, &sasioupage0->
2118 PhyData[i].AttachedDevHandle);
2119 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2120 mpt->m_phy_info[i].port_flags = port_flags;
2121
2122 if (port_flags & DISCOVERY_IN_PROGRESS) {
2123 retrypage0++;
2124 NDBG20(("Discovery in progress, can't "
2125 "verify IO unit config, then NO.%d"
2126 " times retry", retrypage0));
2127 break;
2128 } else {
2129 retrypage0 = 0;
2130 }
2131 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2132 /*
2133 * some PHY configuration described in
2134 * SAS IO Unit Page1
2135 */
2136 readpage1 = 1;
2137 }
2138 }
2139
2140 /*
2141 * retry 30 times if discovery is in process
2142 */
2143 if (retrypage0 && (retrypage0 < 30)) {
2144 drv_usecwait(1000 * 100);
2145 state = IOUC_READ_PAGE0;
2146 break;
2147 } else if (retrypage0 == 30) {
2148 mptsas_log(mpt, CE_WARN,
2149 "!Discovery in progress, can't "
2150 "verify IO unit config, then after"
2151 " 30 times retry, give up!");
2152 state = IOUC_DONE;
2153 rval = DDI_FAILURE;
2154 break;
2155 }
2156
2157 if (readpage1 == 0) {
2158 state = IOUC_DONE;
2159 rval = DDI_SUCCESS;
2160 break;
2161 }
2162
2163 state = IOUC_READ_PAGE1;
2164 break;
2165
2166 case IOUC_READ_PAGE1:
2167 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2168 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2169 goto cleanup;
2170 }
2171
2172 num_phys = ddi_get8(page_accessp,
2173 &sasioupage1->NumPhys);
2174 ASSERT(num_phys == mpt->m_num_phys);
2175 if (num_phys > MPTSAS_MAX_PHYS) {
2176 mptsas_log(mpt, CE_WARN, "Number of phys "
2177 "supported by HBA (%d) is more than max "
2178 "supported by driver (%d). Driver will "
2179 "not attach.", num_phys,
2180 MPTSAS_MAX_PHYS);
2181 rval = DDI_FAILURE;
2182 goto cleanup;
2183 }
2184 for (i = 0; i < num_phys; i++) {
2185 cpdi[i] = ddi_get32(page_accessp,
2186 &sasioupage1->PhyData[i].
2187 ControllerPhyDeviceInfo);
2188 port_flags = ddi_get8(page_accessp,
2189 &sasioupage1->PhyData[i].PortFlags);
2190 mpt->m_phy_info[i].port_num =
2191 ddi_get8(page_accessp,
2192 &sasioupage1->PhyData[i].Port);
2193 mpt->m_phy_info[i].port_flags = port_flags;
2194 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2195
2196 }
2197
2198 state = IOUC_DONE;
2199 rval = DDI_SUCCESS;
2200 break;
2201 }
2202 }
2203 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2204 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2205 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2206 rval = DDI_FAILURE;
2207 goto cleanup;
2208 }
2209 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2210 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2211 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2212 rval = DDI_FAILURE;
2213 goto cleanup;
2214 }
2215
2216 cleanup:
2217 if (free_recv)
2218 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2219 if (free_page)
2220 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2221 if (rval != DDI_SUCCESS) {
2222 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2223 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2224 }
2225 return (rval);
2226 }
2227
2228 /*
2229 * mptsas_get_manufacture_page5
2230 *
2231 * This function will retrieve the base WWID from the adapter. Since this
2232 * function is only called during the initialization process, use handshaking.
2233 */
2234 int
2235 mptsas_get_manufacture_page5(mptsas_t *mpt)
2236 {
2237 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2238 ddi_dma_cookie_t page_cookie;
2239 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2240 ddi_acc_handle_t recv_accessp, page_accessp;
2241 pMpi2ConfigReply_t configreply;
2242 caddr_t recv_memp, page_memp;
2243 int recv_numbytes;
2244 pMpi2ManufacturingPage5_t m5;
2245 uint32_t flagslength;
2246 int rval = DDI_SUCCESS;
2247 uint_t iocstatus;
2248 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2249
2250 MPTSAS_DISABLE_INTR(mpt);
2251
2252 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2253 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2254 rval = DDI_FAILURE;
2255 goto done;
2256 }
2257
2258 /*
2259 * dynamically create a customized dma attribute structure
2260 * that describes the MPT's config reply page request structure.
2261 */
2262 recv_dma_attrs = mpt->m_msg_dma_attr;
2263 recv_dma_attrs.dma_attr_sgllen = 1;
2264 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2265
2266 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2267 &recv_dma_handle, &recv_accessp, &recv_memp,
2268 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2269 rval = DDI_FAILURE;
2270 goto done;
2271 }
2272 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2273 free_recv = B_TRUE;
2274
2275 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2276 configreply = (pMpi2ConfigReply_t)recv_memp;
2277 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2278
2279 /*
2280 * get config reply message
2281 */
2282 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2283 recv_accessp)) {
2284 rval = DDI_FAILURE;
2285 goto done;
2286 }
2287
2288 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2289 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2290 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2291 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2292 goto done;
2293 }
2294
2295 /*
2296 * dynamically create a customized dma attribute structure
2297 * that describes the MPT's config page structure.
2298 */
2299 page_dma_attrs = mpt->m_msg_dma_attr;
2300 page_dma_attrs.dma_attr_sgllen = 1;
2301 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2302
2303 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2304 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2305 &page_cookie) == FALSE) {
2306 rval = DDI_FAILURE;
2307 goto done;
2308 }
2309 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2310 free_page = B_TRUE;
2311
2312 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2313 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2314
2315 /*
2316 * Give reply address to IOC to store config page in and send
2317 * config request out.
2318 */
2319
2320 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2321 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2322 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2323 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2324 MPI2_SGE_FLAGS_IOC_TO_HOST |
2325 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2326
2327 if (mptsas_send_config_request_msg(mpt,
2328 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2329 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2330 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2331 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2332 flagslength, page_cookie.dmac_address)) {
2333 rval = DDI_FAILURE;
2334 goto done;
2335 }
2336
2337 /*
2338 * get reply view handshake
2339 */
2340 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2341 recv_accessp)) {
2342 rval = DDI_FAILURE;
2343 goto done;
2344 }
2345
2346 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2347 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2348 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2349 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2350 goto done;
2351 }
2352
2353 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2354
2355 /*
2356 * Fusion-MPT stores fields in little-endian format. This is
2357 * why the low-order 32 bits are stored first.
2358 */
2359 mpt->un.sasaddr.m_base_wwid_lo =
2360 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2361 mpt->un.sasaddr.m_base_wwid_hi =
2362 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2363
2364 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2365 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2366 NDBG2(("%s%d: failed to create base-wwid property",
2367 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2368 }
2369
2370 /*
2371 * Set the number of PHYs present.
2372 */
2373 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2374
2375 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2376 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2377 NDBG2(("%s%d: failed to create num-phys property",
2378 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2379 }
2380
2381 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2382 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2383 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2384
2385 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2386 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2387 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2388 rval = DDI_FAILURE;
2389 goto done;
2390 }
2391 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2392 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2393 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2394 rval = DDI_FAILURE;
2395 }
2396 done:
2397 /*
2398 * free up memory
2399 */
2400 if (free_recv)
2401 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2402 if (free_page)
2403 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2404 MPTSAS_ENABLE_INTR(mpt);
2405
2406 return (rval);
2407 }
2408
2409 static int
2410 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2411 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2412 va_list ap)
2413 {
2414 #ifndef __lock_lint
2415 _NOTE(ARGUNUSED(ap))
2416 #endif
2417 pMpi2SasPhyPage0_t sasphypage;
2418 int rval = DDI_SUCCESS;
2419 uint16_t *owner_devhdl, *attached_devhdl;
2420 uint8_t *attached_phy_identify;
2421 uint32_t *attached_phy_info;
2422 uint8_t *programmed_link_rate;
2423 uint8_t *hw_link_rate;
2424 uint8_t *change_count;
2425 uint32_t *phy_info;
2426 uint8_t *negotiated_link_rate;
2427 uint32_t page_address;
2428
2429 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2430 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2431 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2432 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2433 iocstatus, iocloginfo);
2434 rval = DDI_FAILURE;
2435 return (rval);
2436 }
2437 page_address = va_arg(ap, uint32_t);
2438 /*
2439 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2440 * are no more pages. If everything is OK up to this point but the
2441 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2442 * signal that device traversal is complete.
2443 */
2444 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2445 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2446 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2447 mpt->m_done_traverse_smp = 1;
2448 }
2449 rval = DDI_FAILURE;
2450 return (rval);
2451 }
2452 owner_devhdl = va_arg(ap, uint16_t *);
2453 attached_devhdl = va_arg(ap, uint16_t *);
2454 attached_phy_identify = va_arg(ap, uint8_t *);
2455 attached_phy_info = va_arg(ap, uint32_t *);
2456 programmed_link_rate = va_arg(ap, uint8_t *);
2457 hw_link_rate = va_arg(ap, uint8_t *);
2458 change_count = va_arg(ap, uint8_t *);
2459 phy_info = va_arg(ap, uint32_t *);
2460 negotiated_link_rate = va_arg(ap, uint8_t *);
2461
2462 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2463
2464 *owner_devhdl =
2465 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2466 *attached_devhdl =
2467 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2468 *attached_phy_identify =
2469 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2470 *attached_phy_info =
2471 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2472 *programmed_link_rate =
2473 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2474 *hw_link_rate =
2475 ddi_get8(accessp, &sasphypage->HwLinkRate);
2476 *change_count =
2477 ddi_get8(accessp, &sasphypage->ChangeCount);
2478 *phy_info =
2479 ddi_get32(accessp, &sasphypage->PhyInfo);
2480 *negotiated_link_rate =
2481 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2482
2483 return (rval);
2484 }
2485
2486 /*
2487 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2488 * and SAS address.
2489 */
2490 int
2491 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2492 smhba_info_t *info)
2493 {
2494 int rval = DDI_SUCCESS;
2495
2496 ASSERT(mutex_owned(&mpt->m_mutex));
2497
2498 /*
2499 * Get the header and config page. reply contains the reply frame,
2500 * which holds status info for the request.
2501 */
2502 rval = mptsas_access_config_page(mpt,
2503 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2504 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2505 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2506 &info->attached_devhdl, &info->attached_phy_identify,
2507 &info->attached_phy_info, &info->programmed_link_rate,
2508 &info->hw_link_rate, &info->change_count,
2509 &info->phy_info, &info->negotiated_link_rate);
2510
2511 return (rval);
2512 }
2513
2514 static int
2515 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2516 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2517 va_list ap)
2518 {
2519 #ifndef __lock_lint
2520 _NOTE(ARGUNUSED(ap))
2521 #endif
2522 pMpi2SasPhyPage1_t sasphypage;
2523 int rval = DDI_SUCCESS;
2524
2525 uint32_t *invalid_dword_count;
2526 uint32_t *running_disparity_error_count;
2527 uint32_t *loss_of_dword_sync_count;
2528 uint32_t *phy_reset_problem_count;
2529 uint32_t page_address;
2530
2531 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2532 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2533 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2534 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2535 iocstatus, iocloginfo);
2536 rval = DDI_FAILURE;
2537 return (rval);
2538 }
2539 page_address = va_arg(ap, uint32_t);
2540 /*
2541 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2542 * are no more pages. If everything is OK up to this point but the
2543 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2544 * signal that device traversal is complete.
2545 */
2546 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2547 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2548 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2549 mpt->m_done_traverse_smp = 1;
2550 }
2551 rval = DDI_FAILURE;
2552 return (rval);
2553 }
2554
2555 invalid_dword_count = va_arg(ap, uint32_t *);
2556 running_disparity_error_count = va_arg(ap, uint32_t *);
2557 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2558 phy_reset_problem_count = va_arg(ap, uint32_t *);
2559
2560 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2561
2562 *invalid_dword_count =
2563 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2564 *running_disparity_error_count =
2565 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2566 *loss_of_dword_sync_count =
2567 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2568 *phy_reset_problem_count =
2569 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2570
2571 return (rval);
2572 }
2573
2574 /*
2575 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2576 * and SAS address.
2577 */
2578 int
2579 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2580 smhba_info_t *info)
2581 {
2582 int rval = DDI_SUCCESS;
2583
2584 ASSERT(mutex_owned(&mpt->m_mutex));
2585
2586 /*
2587 * Get the header and config page. reply contains the reply frame,
2588 * which holds status info for the request.
2589 */
2590 rval = mptsas_access_config_page(mpt,
2591 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2592 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2593 mptsas_sasphypage_1_cb, page_address,
2594 &info->invalid_dword_count,
2595 &info->running_disparity_error_count,
2596 &info->loss_of_dword_sync_count,
2597 &info->phy_reset_problem_count);
2598
2599 return (rval);
2600 }
2601 /*
2602 * mptsas_get_manufacture_page0
2603 *
2604 * This function will retrieve the base
2605 * Chip name, Board Name,Board Trace number from the adapter.
2606 * Since this function is only called during the
2607 * initialization process, use handshaking.
2608 */
2609 int
2610 mptsas_get_manufacture_page0(mptsas_t *mpt)
2611 {
2612 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2613 ddi_dma_cookie_t page_cookie;
2614 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2615 ddi_acc_handle_t recv_accessp, page_accessp;
2616 pMpi2ConfigReply_t configreply;
2617 caddr_t recv_memp, page_memp;
2618 int recv_numbytes;
2619 pMpi2ManufacturingPage0_t m0;
2620 uint32_t flagslength;
2621 int rval = DDI_SUCCESS;
2622 uint_t iocstatus;
2623 uint8_t i = 0;
2624 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2625
2626 MPTSAS_DISABLE_INTR(mpt);
2627
2628 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2629 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2630 rval = DDI_FAILURE;
2631 goto done;
2632 }
2633
2634 /*
2635 * dynamically create a customized dma attribute structure
2636 * that describes the MPT's config reply page request structure.
2637 */
2638 recv_dma_attrs = mpt->m_msg_dma_attr;
2639 recv_dma_attrs.dma_attr_sgllen = 1;
2640 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2641
2642 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2643 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2644 NULL) == FALSE) {
2645 rval = DDI_FAILURE;
2646 goto done;
2647 }
2648 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2649 free_recv = B_TRUE;
2650
2651 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2652 configreply = (pMpi2ConfigReply_t)recv_memp;
2653 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2654
2655 /*
2656 * get config reply message
2657 */
2658 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2659 recv_accessp)) {
2660 rval = DDI_FAILURE;
2661 goto done;
2662 }
2663
2664 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2665 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2666 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2667 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2668 goto done;
2669 }
2670
2671 /*
2672 * dynamically create a customized dma attribute structure
2673 * that describes the MPT's config page structure.
2674 */
2675 page_dma_attrs = mpt->m_msg_dma_attr;
2676 page_dma_attrs.dma_attr_sgllen = 1;
2677 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2678
2679 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2680 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2681 &page_cookie) == FALSE) {
2682 rval = DDI_FAILURE;
2683 goto done;
2684 }
2685 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2686 free_page = B_TRUE;
2687
2688 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2689 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2690
2691 /*
2692 * Give reply address to IOC to store config page in and send
2693 * config request out.
2694 */
2695
2696 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2697 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2698 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2699 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2700 MPI2_SGE_FLAGS_IOC_TO_HOST |
2701 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2702
2703 if (mptsas_send_config_request_msg(mpt,
2704 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2705 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2706 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2707 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2708 flagslength, page_cookie.dmac_address)) {
2709 rval = DDI_FAILURE;
2710 goto done;
2711 }
2712
2713 /*
2714 * get reply view handshake
2715 */
2716 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2717 recv_accessp)) {
2718 rval = DDI_FAILURE;
2719 goto done;
2720 }
2721
2722 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2723 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2724 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2725 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2726 goto done;
2727 }
2728
2729 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2730
2731 /*
2732 * Fusion-MPT stores fields in little-endian format. This is
2733 * why the low-order 32 bits are stored first.
2734 */
2735
2736 for (i = 0; i < 16; i++) {
2737 mpt->m_MANU_page0.ChipName[i] =
2738 ddi_get8(page_accessp,
2739 (uint8_t *)(void *)&m0->ChipName[i]);
2740 }
2741
2742 for (i = 0; i < 8; i++) {
2743 mpt->m_MANU_page0.ChipRevision[i] =
2744 ddi_get8(page_accessp,
2745 (uint8_t *)(void *)&m0->ChipRevision[i]);
2746 }
2747
2748 for (i = 0; i < 16; i++) {
2749 mpt->m_MANU_page0.BoardName[i] =
2750 ddi_get8(page_accessp,
2751 (uint8_t *)(void *)&m0->BoardName[i]);
2752 }
2753
2754 for (i = 0; i < 16; i++) {
2755 mpt->m_MANU_page0.BoardAssembly[i] =
2756 ddi_get8(page_accessp,
2757 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2758 }
2759
2760 for (i = 0; i < 16; i++) {
2761 mpt->m_MANU_page0.BoardTracerNumber[i] =
2762 ddi_get8(page_accessp,
2763 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2764 }
2765
2766 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2767 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2768 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2769 rval = DDI_FAILURE;
2770 goto done;
2771 }
2772 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2773 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2774 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2775 rval = DDI_FAILURE;
2776 }
2777 done:
2778 /*
2779 * free up memory
2780 */
2781 if (free_recv)
2782 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2783 if (free_page)
2784 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2785 MPTSAS_ENABLE_INTR(mpt);
2786
2787 return (rval);
2788 }