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