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