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