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