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