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