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