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