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