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