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