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