xref: /titanic_51/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c (revision 39fd84a866206a99cbb6b6e63e0c38a367aaa88e)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27  */
28 
29 /*
30  * Copyright (c) 2000 to 2010, LSI Corporation.
31  * All rights reserved.
32  *
33  * Redistribution and use in source and binary forms of all code within
34  * this file that is exclusively owned by LSI, with or without
35  * modification, is permitted provided that, in addition to the CDDL 1.0
36  * License requirements, the following conditions are met:
37  *
38  *    Neither the name of the author nor the names of its contributors may be
39  *    used to endorse or promote products derived from this software without
40  *    specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
45  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
46  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
48  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
49  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
50  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53  * DAMAGE.
54  */
55 
56 /*
57  * mptsas_raid - This file contains all the RAID related functions for the
58  * MPT interface.
59  */
60 
61 #if defined(lint) || defined(DEBUG)
62 #define	MPTSAS_DEBUG
63 #endif
64 
65 #define	MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX	2
66 
67 /*
68  * standard header files
69  */
70 #include <sys/note.h>
71 #include <sys/scsi/scsi.h>
72 #include <sys/byteorder.h>
73 #include <sys/raidioctl.h>
74 
75 #pragma pack(1)
76 
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
80 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
81 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
82 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
83 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
84 
85 #pragma pack()
86 
87 /*
88  * private header files.
89  */
90 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
91 
92 static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
93 
94 extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
95 extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
96 extern mptsas_target_t *mptsas_tgt_alloc(refhash_t *, uint16_t,
97     uint64_t, uint32_t, mptsas_phymask_t, uint8_t);
98 
99 static int
100 mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
101     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
102     va_list ap)
103 {
104 #ifndef __lock_lint
105 	_NOTE(ARGUNUSED(ap))
106 #endif
107 	pMpi2RaidConfigurationPage0_t	raidconfig_page0;
108 	pMpi2RaidConfig0ConfigElement_t	element;
109 	uint32_t *confignum;
110 	int rval = DDI_SUCCESS, i;
111 	uint8_t numelements, vol, disk;
112 	uint16_t elementtype, voldevhandle;
113 	uint16_t etype_vol, etype_pd, etype_hs;
114 	uint16_t etype_oce;
115 	m_raidconfig_t *raidconfig;
116 	uint64_t raidwwn;
117 	uint32_t native;
118 	mptsas_target_t	*ptgt;
119 	uint32_t configindex;
120 
121 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
122 		return (DDI_FAILURE);
123 	}
124 
125 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
126 		mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 "
127 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
128 		    iocstatus, iocloginfo);
129 		rval = DDI_FAILURE;
130 		return (rval);
131 	}
132 	confignum = va_arg(ap,  uint32_t *);
133 	configindex = va_arg(ap, uint32_t);
134 	raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp;
135 	/*
136 	 * Get all RAID configurations.
137 	 */
138 	etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT;
139 	etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT;
140 	etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT;
141 	etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT;
142 	/*
143 	 * Set up page address for next time through.
144 	 */
145 	*confignum =  ddi_get8(accessp,
146 	    &raidconfig_page0->ConfigNum);
147 
148 	/*
149 	 * Point to the right config in the structure.
150 	 * Increment the number of valid RAID configs.
151 	 */
152 	raidconfig = &mpt->m_raidconfig[configindex];
153 	mpt->m_num_raid_configs++;
154 
155 	/*
156 	 * Set the native flag if this is not a foreign
157 	 * configuration.
158 	 */
159 	native = ddi_get32(accessp, &raidconfig_page0->Flags);
160 	if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) {
161 		native = FALSE;
162 	} else {
163 		native = TRUE;
164 	}
165 	raidconfig->m_native = (uint8_t)native;
166 
167 	/*
168 	 * Get volume information for the volumes in the
169 	 * config.
170 	 */
171 	numelements = ddi_get8(accessp, &raidconfig_page0->NumElements);
172 	vol = 0;
173 	disk = 0;
174 	element = (pMpi2RaidConfig0ConfigElement_t)
175 	    &raidconfig_page0->ConfigElement;
176 
177 	for (i = 0; ((i < numelements) && native); i++, element++) {
178 		/*
179 		 * Get the element type.  Could be Volume,
180 		 * PhysDisk, Hot Spare, or Online Capacity
181 		 * Expansion PhysDisk.
182 		 */
183 		elementtype = ddi_get16(accessp, &element->ElementFlags);
184 		elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
185 
186 		/*
187 		 * For volumes, get the RAID settings and the
188 		 * WWID.
189 		 */
190 		if (elementtype == etype_vol) {
191 			voldevhandle = ddi_get16(accessp,
192 			    &element->VolDevHandle);
193 			raidconfig->m_raidvol[vol].m_israid = 1;
194 			raidconfig->m_raidvol[vol].
195 			    m_raidhandle = voldevhandle;
196 			/*
197 			 * Get the settings for the raid
198 			 * volume.  This includes the
199 			 * DevHandles for the disks making up
200 			 * the raid volume.
201 			 */
202 			if (mptsas_get_raid_settings(mpt,
203 			    &raidconfig->m_raidvol[vol]))
204 				continue;
205 
206 			/*
207 			 * Get the WWID of the RAID volume for
208 			 * SAS HBA
209 			 */
210 			if (mptsas_get_raid_wwid(mpt,
211 			    &raidconfig->m_raidvol[vol]))
212 				continue;
213 
214 			raidwwn = raidconfig->m_raidvol[vol].
215 			    m_raidwwid;
216 
217 			/*
218 			 * RAID uses phymask of 0.
219 			 */
220 			ptgt = mptsas_tgt_alloc(mpt->m_targets,
221 			    voldevhandle, raidwwn, 0, 0, 0);
222 
223 			raidconfig->m_raidvol[vol].m_raidtgt =
224 			    ptgt;
225 
226 			/*
227 			 * Increment volume index within this
228 			 * raid config.
229 			 */
230 			vol++;
231 		} else if ((elementtype == etype_pd) ||
232 		    (elementtype == etype_hs) ||
233 		    (elementtype == etype_oce)) {
234 			/*
235 			 * For all other element types, put
236 			 * their DevHandles in the phys disk
237 			 * list of the config.  These are all
238 			 * some variation of a Phys Disk and
239 			 * this list is used to keep these
240 			 * disks from going online.
241 			 */
242 			raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp,
243 			    &element->PhysDiskDevHandle);
244 
245 			/*
246 			 * Increment disk index within this
247 			 * raid config.
248 			 */
249 			disk++;
250 		}
251 	}
252 
253 	return (rval);
254 }
255 
256 int
257 mptsas_get_raid_info(mptsas_t *mpt)
258 {
259 	int rval = DDI_SUCCESS;
260 	uint32_t confignum, pageaddress;
261 	uint8_t configindex;
262 
263 	ASSERT(mutex_owned(&mpt->m_mutex));
264 
265 	/*
266 	 * Clear all RAID info before starting.
267 	 */
268 	bzero(mpt->m_raidconfig, sizeof (mpt->m_raidconfig));
269 	mpt->m_num_raid_configs = 0;
270 
271 	configindex = 0;
272 	confignum = 0xff;
273 	pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum;
274 	while (rval == DDI_SUCCESS) {
275 		/*
276 		 * Get the header and config page.  reply contains the reply
277 		 * frame, which holds status info for the request.
278 		 */
279 		rval = mptsas_access_config_page(mpt,
280 		    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
281 		    MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress,
282 		    mptsas_raidconf_page_0_cb, &confignum, configindex);
283 		configindex++;
284 		pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM |
285 		    confignum;
286 	}
287 
288 	return (rval);
289 }
290 
291 static int
292 mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
293     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
294     va_list ap)
295 {
296 #ifndef __lock_lint
297 	_NOTE(ARGUNUSED(ap))
298 #endif
299 	pMpi2RaidVolPage0_t raidpage;
300 	int rval = DDI_SUCCESS, i;
301 	mptsas_raidvol_t *raidvol;
302 	uint8_t	numdisks, volstate, voltype, physdisknum;
303 	uint32_t volsetting;
304 	uint32_t statusflags, resync_flag;
305 
306 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
307 		return (DDI_FAILURE);
308 
309 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
310 		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb "
311 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
312 		    iocstatus, iocloginfo);
313 		rval = DDI_FAILURE;
314 		return (rval);
315 	}
316 
317 	raidvol = va_arg(ap,  mptsas_raidvol_t *);
318 
319 	raidpage = (pMpi2RaidVolPage0_t)page_memp;
320 	volstate = ddi_get8(accessp, &raidpage->VolumeState);
321 	volsetting = ddi_get32(accessp,
322 	    (uint32_t *)(void *)&raidpage->VolumeSettings);
323 	statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags);
324 	voltype = ddi_get8(accessp, &raidpage->VolumeType);
325 
326 	raidvol->m_state = volstate;
327 	raidvol->m_statusflags = statusflags;
328 	/*
329 	 * Volume size is not used right now. Set to 0.
330 	 */
331 	raidvol->m_raidsize = 0;
332 	raidvol->m_settings = volsetting;
333 	raidvol->m_raidlevel = voltype;
334 
335 	if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) {
336 		mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n",
337 		    raidvol->m_raidhandle);
338 	}
339 
340 	if (statusflags &
341 	    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
342 		mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n",
343 		    raidvol->m_raidhandle);
344 	}
345 
346 	resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
347 	switch (volstate) {
348 	case MPI2_RAID_VOL_STATE_OPTIMAL:
349 		mptsas_log(mpt, CE_NOTE, "?Volume %d is "
350 		    "optimal\n", raidvol->m_raidhandle);
351 		break;
352 	case MPI2_RAID_VOL_STATE_DEGRADED:
353 		if ((statusflags & resync_flag) == 0) {
354 			mptsas_log(mpt, CE_WARN, "Volume %d "
355 			    "is degraded\n",
356 			    raidvol->m_raidhandle);
357 		}
358 		break;
359 	case MPI2_RAID_VOL_STATE_FAILED:
360 		mptsas_log(mpt, CE_WARN, "Volume %d is "
361 		    "failed\n", raidvol->m_raidhandle);
362 		break;
363 	case MPI2_RAID_VOL_STATE_MISSING:
364 		mptsas_log(mpt, CE_WARN, "Volume %d is "
365 		    "missing\n", raidvol->m_raidhandle);
366 		break;
367 	default:
368 		break;
369 	}
370 	numdisks = raidpage->NumPhysDisks;
371 	raidvol->m_ndisks = numdisks;
372 	for (i = 0; i < numdisks; i++) {
373 		physdisknum = raidpage->PhysDisk[i].PhysDiskNum;
374 		raidvol->m_disknum[i] = physdisknum;
375 		if (mptsas_get_physdisk_settings(mpt, raidvol,
376 		    physdisknum))
377 			break;
378 	}
379 	return (rval);
380 }
381 
382 int
383 mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
384 {
385 	int rval = DDI_SUCCESS;
386 	uint32_t page_address;
387 
388 	ASSERT(mutex_owned(&mpt->m_mutex));
389 
390 	/*
391 	 * Get the header and config page.  reply contains the reply frame,
392 	 * which holds status info for the request.
393 	 */
394 	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
395 	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
396 	rval = mptsas_access_config_page(mpt,
397 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
398 	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address,
399 	    mptsas_raidvol_page_0_cb, raidvol);
400 
401 	return (rval);
402 }
403 
404 static int
405 mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
406     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
407     va_list ap)
408 {
409 #ifndef __lock_lint
410 	_NOTE(ARGUNUSED(ap))
411 #endif
412 	pMpi2RaidVolPage1_t	raidpage;
413 	int			rval = DDI_SUCCESS, i;
414 	uint8_t			*sas_addr = NULL;
415 	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
416 	uint64_t		*sas_wwn;
417 
418 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
419 		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb "
420 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
421 		    iocstatus, iocloginfo);
422 		rval = DDI_FAILURE;
423 		return (rval);
424 	}
425 	sas_wwn = va_arg(ap, uint64_t *);
426 
427 	raidpage = (pMpi2RaidVolPage1_t)page_memp;
428 	sas_addr = (uint8_t *)(&raidpage->WWID);
429 	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
430 		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
431 	}
432 	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
433 	*sas_wwn = LE_64(*sas_wwn);
434 	return (rval);
435 }
436 
437 static int
438 mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
439 {
440 	int rval = DDI_SUCCESS;
441 	uint32_t page_address;
442 	uint64_t sas_wwn;
443 
444 	ASSERT(mutex_owned(&mpt->m_mutex));
445 
446 	/*
447 	 * Get the header and config page.  reply contains the reply frame,
448 	 * which holds status info for the request.
449 	 */
450 	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
451 	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
452 	rval = mptsas_access_config_page(mpt,
453 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
454 	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address,
455 	    mptsas_raidvol_page_1_cb, &sas_wwn);
456 
457 	/*
458 	 * Get the required information from the page.
459 	 */
460 	if (rval == DDI_SUCCESS) {
461 
462 		/*
463 		 * replace top nibble of WWID of RAID to '3' for OBP
464 		 */
465 		sas_wwn = MPTSAS_RAID_WWID(sas_wwn);
466 		raidvol->m_raidwwid = sas_wwn;
467 	}
468 
469 	return (rval);
470 }
471 
472 static int
473 mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
474     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
475     va_list ap)
476 {
477 #ifndef __lock_lint
478 	_NOTE(ARGUNUSED(ap))
479 #endif
480 	pMpi2RaidPhysDiskPage0_t	diskpage;
481 	int			rval = DDI_SUCCESS;
482 	uint16_t		*devhdl;
483 	uint8_t			*state;
484 
485 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
486 		return (DDI_FAILURE);
487 
488 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
489 		mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
490 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
491 		    iocstatus, iocloginfo);
492 		rval = DDI_FAILURE;
493 		return (rval);
494 	}
495 	devhdl = va_arg(ap, uint16_t *);
496 	state = va_arg(ap, uint8_t *);
497 	diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
498 	*devhdl = ddi_get16(accessp, &diskpage->DevHandle);
499 	*state = ddi_get8(accessp, &diskpage->PhysDiskState);
500 	return (rval);
501 }
502 
503 int
504 mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
505     uint8_t physdisknum)
506 {
507 	int			rval = DDI_SUCCESS, i;
508 	uint8_t			state;
509 	uint16_t		devhdl;
510 	uint32_t		page_address;
511 
512 	ASSERT(mutex_owned(&mpt->m_mutex));
513 
514 	/*
515 	 * Get the header and config page.  reply contains the reply frame,
516 	 * which holds status info for the request.
517 	 */
518 	page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
519 	    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
520 	rval = mptsas_access_config_page(mpt,
521 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
522 	    MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
523 	    mptsas_raidphydsk_page_0_cb, &devhdl, &state);
524 
525 	/*
526 	 * Get the required information from the page.
527 	 */
528 	if (rval == DDI_SUCCESS) {
529 		for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
530 			/* find the correct position in the arrays */
531 			if (raidvol->m_disknum[i] == physdisknum)
532 				break;
533 		}
534 		raidvol->m_devhdl[i] = devhdl;
535 
536 		switch (state) {
537 			case MPI2_RAID_PD_STATE_OFFLINE:
538 				raidvol->m_diskstatus[i] =
539 				    RAID_DISKSTATUS_FAILED;
540 				break;
541 
542 			case MPI2_RAID_PD_STATE_HOT_SPARE:
543 			case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
544 			case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
545 				break;
546 
547 			case MPI2_RAID_PD_STATE_DEGRADED:
548 			case MPI2_RAID_PD_STATE_OPTIMAL:
549 			case MPI2_RAID_PD_STATE_REBUILDING:
550 			case MPI2_RAID_PD_STATE_ONLINE:
551 			default:
552 				raidvol->m_diskstatus[i] =
553 				    RAID_DISKSTATUS_GOOD;
554 				break;
555 		}
556 	}
557 
558 	return (rval);
559 }
560 
561 /*
562  * RAID Action for System Shutdown. This request uses the dedicated TM slot to
563  * avoid a call to mptsas_save_cmd.  Since Solaris requires that the mutex is
564  * not held during the mptsas_quiesce function, this RAID action must not use
565  * the normal code path of requests and replies.
566  */
567 void
568 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
569 {
570 	pMpi2RaidActionRequest_t	action;
571 	uint8_t				ir_active = FALSE, reply_type;
572 	uint8_t				function, found_reply = FALSE;
573 	uint16_t			SMID, action_type;
574 	mptsas_slots_t			*slots = mpt->m_active;
575 	int				config, vol;
576 	mptsas_cmd_t			*cmd;
577 	uint32_t			reply_addr;
578 	uint64_t			request_desc;
579 	int				cnt;
580 	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
581 	pMPI2DefaultReply_t		reply;
582 	pMpi2AddressReplyDescriptor_t	address_reply;
583 
584 	/*
585 	 * Before doing the system shutdown RAID Action, make sure that the IOC
586 	 * supports IR and make sure there is a valid volume for the request.
587 	 */
588 	if (mpt->m_ir_capable) {
589 		for (config = 0; (config < mpt->m_num_raid_configs) &&
590 		    (!ir_active); config++) {
591 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
592 				if (mpt->m_raidconfig[config].m_raidvol[vol].
593 				    m_israid) {
594 					ir_active = TRUE;
595 					break;
596 				}
597 			}
598 		}
599 	}
600 	if (!ir_active) {
601 		return;
602 	}
603 
604 	/*
605 	 * If TM slot is already being used (highly unlikely), show message and
606 	 * don't issue the RAID action.
607 	 */
608 	if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
609 		mptsas_log(mpt, CE_WARN, "RAID Action slot in use.  Cancelling"
610 		    " System Shutdown RAID Action.\n");
611 		return;
612 	}
613 
614 	/*
615 	 * Create the cmd and put it in the dedicated TM slot.
616 	 */
617 	cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
618 	bzero((caddr_t)cmd, sizeof (*cmd));
619 	cmd->cmd_pkt = NULL;
620 	cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
621 	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
622 
623 	/*
624 	 * Form message for raid action.
625 	 */
626 	action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
627 	    (mpt->m_req_frame_size * cmd->cmd_slot));
628 	bzero(action, mpt->m_req_frame_size);
629 	action->Function = MPI2_FUNCTION_RAID_ACTION;
630 	action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
631 
632 	/*
633 	 * Send RAID Action.
634 	 */
635 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
636 	    DDI_DMA_SYNC_FORDEV);
637 	request_desc = (cmd->cmd_slot << 16) +
638 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
639 	MPTSAS_START_CMD(mpt, request_desc);
640 
641 	/*
642 	 * Even though reply does not matter because the system is shutting
643 	 * down, wait no more than 5 seconds here to get the reply just because
644 	 * we don't want to leave it hanging if it's coming.  Poll because
645 	 * interrupts are disabled when this function is called.
646 	 */
647 	for (cnt = 0; cnt < 5000; cnt++) {
648 		/*
649 		 * Check for a reply.
650 		 */
651 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
652 		    DDI_DMA_SYNC_FORCPU);
653 
654 		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
655 		    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
656 
657 		if (ddi_get32(mpt->m_acc_post_queue_hdl,
658 		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
659 		    ddi_get32(mpt->m_acc_post_queue_hdl,
660 		    &reply_desc_union->Words.High) == 0xFFFFFFFF) {
661 			drv_usecwait(1000);
662 			continue;
663 		}
664 
665 		/*
666 		 * There is a reply.  If it's not an address reply, ignore it.
667 		 */
668 		reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
669 		    &reply_desc_union->Default.ReplyFlags);
670 		reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
671 		if (reply_type != MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
672 			goto clear_and_continue;
673 		}
674 
675 		/*
676 		 * SMID must be the TM slot since that's what we're using for
677 		 * this RAID action.  If not, ignore this reply.
678 		 */
679 		address_reply =
680 		    (pMpi2AddressReplyDescriptor_t)reply_desc_union;
681 		SMID = ddi_get16(mpt->m_acc_post_queue_hdl,
682 		    &address_reply->SMID);
683 		if (SMID != MPTSAS_TM_SLOT(mpt)) {
684 			goto clear_and_continue;
685 		}
686 
687 		/*
688 		 * If reply frame is not in the proper range ignore it.
689 		 */
690 		reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
691 		    &address_reply->ReplyFrameAddress);
692 		if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
693 		    (reply_addr >= (mpt->m_reply_frame_dma_addr +
694 		    (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
695 		    ((reply_addr - mpt->m_reply_frame_dma_addr) %
696 		    mpt->m_reply_frame_size != 0)) {
697 			goto clear_and_continue;
698 		}
699 
700 		/*
701 		 * If not a RAID action reply ignore it.
702 		 */
703 		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
704 		    DDI_DMA_SYNC_FORCPU);
705 		reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame +
706 		    (reply_addr - mpt->m_reply_frame_dma_addr));
707 		function = ddi_get8(mpt->m_acc_reply_frame_hdl,
708 		    &reply->Function);
709 		if (function != MPI2_FUNCTION_RAID_ACTION) {
710 			goto clear_and_continue;
711 		}
712 
713 		/*
714 		 * Finally, make sure this is the System Shutdown RAID action.
715 		 * If not, ignore reply.
716 		 */
717 		action_type = ddi_get16(mpt->m_acc_reply_frame_hdl,
718 		    &reply->FunctionDependent1);
719 		if (action_type !=
720 		    MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
721 			goto clear_and_continue;
722 		}
723 		found_reply = TRUE;
724 
725 clear_and_continue:
726 		/*
727 		 * Clear the reply descriptor for re-use and increment index.
728 		 */
729 		ddi_put64(mpt->m_acc_post_queue_hdl,
730 		    &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index],
731 		    0xFFFFFFFFFFFFFFFF);
732 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
733 		    DDI_DMA_SYNC_FORDEV);
734 
735 		/*
736 		 * Update the global reply index and keep looking for the
737 		 * reply if not found yet.
738 		 */
739 		if (++mpt->m_post_index == mpt->m_post_queue_depth) {
740 			mpt->m_post_index = 0;
741 		}
742 		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
743 		    mpt->m_post_index);
744 		if (!found_reply) {
745 			continue;
746 		}
747 
748 		break;
749 	}
750 
751 	/*
752 	 * clear the used slot as the last step.
753 	 */
754 	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
755 }
756 
757 int
758 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
759 {
760 	int		config, i = 0, vol = (-1);
761 
762 	for (config = 0; (config < mpt->m_num_raid_configs) && (vol != i);
763 	    config++) {
764 		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
765 			if (mpt->m_raidconfig[config].m_raidvol[i].
766 			    m_raidhandle == volid) {
767 				vol = i;
768 				break;
769 			}
770 		}
771 	}
772 
773 	if (vol < 0) {
774 		mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
775 		    "target.");
776 		return (-1);
777 	}
778 
779 	mpt->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
780 	mpt->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
781 	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
782 		mpt->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
783 		mpt->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
784 	}
785 
786 	return (0);
787 }
788