xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c (revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright (c) 2000 to 2009, LSI Corporation.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms of all code within
32  * this file that is exclusively owned by LSI, with or without
33  * modification, is permitted provided that, in addition to the CDDL 1.0
34  * License requirements, the following conditions are met:
35  *
36  *    Neither the name of the author nor the names of its contributors may be
37  *    used to endorse or promote products derived from this software without
38  *    specific prior written permission.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
45  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
46  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
47  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
48  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
51  * DAMAGE.
52  */
53 
54 /*
55  * mptsas_raid - This file contains all the RAID related functions for the
56  * MPT interface.
57  */
58 
59 #if defined(lint) || defined(DEBUG)
60 #define	MPTSAS_DEBUG
61 #endif
62 
63 #define	MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX	2
64 
65 /*
66  * standard header files
67  */
68 #include <sys/note.h>
69 #include <sys/scsi/scsi.h>
70 #include <sys/byteorder.h>
71 #include <sys/raidioctl.h>
72 
73 #pragma pack(1)
74 
75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
80 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h>
81 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
82 
83 #pragma pack()
84 
85 /*
86  * private header files.
87  */
88 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
89 
90 static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
91 
92 extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
93 extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
94 extern mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t,
95     uint64_t, uint32_t, uint8_t, uint8_t);
96 
97 static int
98 mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
99     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
100     va_list ap)
101 {
102 #ifndef __lock_lint
103 	_NOTE(ARGUNUSED(ap))
104 #endif
105 	pMpi2RaidConfigurationPage0_t	raidconfig_page0;
106 	pMpi2RaidConfig0ConfigElement_t	element;
107 	uint32_t *confignum;
108 	int rval = DDI_SUCCESS, i;
109 	uint8_t numelements, vol, disk;
110 	uint16_t elementtype, voldevhandle;
111 	uint16_t etype_vol, etype_pd, etype_hs;
112 	uint16_t etype_oce;
113 	mptsas_slots_t *slots = mpt->m_active;
114 	m_raidconfig_t *raidconfig;
115 	uint64_t raidwwn;
116 	uint32_t native;
117 	mptsas_target_t	*ptgt;
118 	uint32_t configindex;
119 
120 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
121 		return (DDI_FAILURE);
122 	}
123 
124 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
125 		mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 "
126 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
127 		    iocstatus, iocloginfo);
128 		rval = DDI_FAILURE;
129 		return (rval);
130 	}
131 	confignum = va_arg(ap,  uint32_t *);
132 	configindex = va_arg(ap, uint32_t);
133 	raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp;
134 	/*
135 	 * Get all RAID configurations.
136 	 */
137 	etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT;
138 	etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT;
139 	etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT;
140 	etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT;
141 	/*
142 	 * Set up page address for next time through.
143 	 */
144 	*confignum =  ddi_get8(accessp,
145 	    &raidconfig_page0->ConfigNum);
146 
147 	/*
148 	 * Point to the right config in the structure.
149 	 * Increment the number of valid RAID configs.
150 	 */
151 	raidconfig = &slots->m_raidconfig[configindex];
152 	slots->m_num_raid_configs++;
153 
154 	/*
155 	 * Set the native flag if this is not a foreign
156 	 * configuration.
157 	 */
158 	native = ddi_get32(accessp, &raidconfig_page0->Flags);
159 	if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) {
160 		native = FALSE;
161 	} else {
162 		native = TRUE;
163 	}
164 	raidconfig->m_native = (uint8_t)native;
165 
166 	/*
167 	 * Get volume information for the volumes in the
168 	 * config.
169 	 */
170 	numelements = ddi_get8(accessp, &raidconfig_page0->NumElements);
171 	vol = 0;
172 	disk = 0;
173 	element = (pMpi2RaidConfig0ConfigElement_t)
174 	    &raidconfig_page0->ConfigElement;
175 
176 	for (i = 0; i < numelements; i++, element++) {
177 		/*
178 		 * Get the element type.  Could be Volume,
179 		 * PhysDisk, Hot Spare, or Online Capacity
180 		 * Expansion PhysDisk.
181 		 */
182 		elementtype = ddi_get16(accessp, &element->ElementFlags);
183 		elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
184 
185 		/*
186 		 * For volumes, get the RAID settings and the
187 		 * WWID.
188 		 */
189 		if (elementtype == etype_vol) {
190 			voldevhandle = ddi_get16(accessp,
191 			    &element->VolDevHandle);
192 			raidconfig->m_raidvol[vol].m_israid = 1;
193 			raidconfig->m_raidvol[vol].
194 			    m_raidhandle = voldevhandle;
195 			/*
196 			 * Get the settings for the raid
197 			 * volume.  This includes the
198 			 * DevHandles for the disks making up
199 			 * the raid volume.
200 			 */
201 			if (mptsas_get_raid_settings(mpt,
202 			    &raidconfig->m_raidvol[vol]))
203 				continue;
204 
205 			/*
206 			 * Get the WWID of the RAID volume for
207 			 * SAS HBA
208 			 */
209 			if (mptsas_get_raid_wwid(mpt,
210 			    &raidconfig->m_raidvol[vol]))
211 				continue;
212 
213 			raidwwn = raidconfig->m_raidvol[vol].
214 			    m_raidwwid;
215 
216 			/*
217 			 * RAID uses phymask of 0.
218 			 */
219 			ptgt = mptsas_tgt_alloc(&slots->m_tgttbl,
220 			    voldevhandle, raidwwn, 0, 0, 0);
221 
222 			raidconfig->m_raidvol[vol].m_raidtgt =
223 			    ptgt;
224 
225 			/*
226 			 * Increment volume index within this
227 			 * raid config.
228 			 */
229 			vol++;
230 		} else if ((elementtype == etype_pd) ||
231 		    (elementtype == etype_hs) ||
232 		    (elementtype == etype_oce)) {
233 			/*
234 			 * For all other element types, put
235 			 * their DevHandles in the phys disk
236 			 * list of the config.  These are all
237 			 * some variation of a Phys Disk and
238 			 * this list is used to keep these
239 			 * disks from going online.
240 			 */
241 			raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp,
242 			    &element->PhysDiskDevHandle);
243 
244 			/*
245 			 * Increment disk index within this
246 			 * raid config.
247 			 */
248 			disk++;
249 		}
250 	}
251 
252 	return (rval);
253 }
254 
255 int
256 mptsas_get_raid_info(mptsas_t *mpt)
257 {
258 	int rval = DDI_SUCCESS;
259 	uint32_t confignum, pageaddress;
260 	uint8_t configindex;
261 	mptsas_slots_t *slots = mpt->m_active;
262 
263 	ASSERT(mutex_owned(&mpt->m_mutex));
264 
265 	/*
266 	 * Clear all RAID info before starting.
267 	 */
268 	bzero(slots->m_raidconfig, sizeof (slots->m_raidconfig));
269 	slots->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 done:
470 	return (rval);
471 }
472 
473 static int
474 mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
475     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
476     va_list ap)
477 {
478 #ifndef __lock_lint
479 	_NOTE(ARGUNUSED(ap))
480 #endif
481 	pMpi2RaidPhysDiskPage0_t	diskpage;
482 	int			rval = DDI_SUCCESS;
483 	uint16_t		*devhdl;
484 	uint8_t			*state;
485 
486 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
487 		return (DDI_FAILURE);
488 
489 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
490 		mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
491 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
492 		    iocstatus, iocloginfo);
493 		rval = DDI_FAILURE;
494 		return (rval);
495 	}
496 	devhdl = va_arg(ap, uint16_t *);
497 	state = va_arg(ap, uint8_t *);
498 	diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
499 	*devhdl = ddi_get16(accessp, &diskpage->DevHandle);
500 	*state = ddi_get8(accessp, &diskpage->PhysDiskState);
501 	return (rval);
502 }
503 
504 int
505 mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
506     uint8_t physdisknum)
507 {
508 	int			rval = DDI_SUCCESS, i;
509 	uint8_t			state;
510 	uint16_t		devhdl;
511 	uint32_t		page_address;
512 
513 	ASSERT(mutex_owned(&mpt->m_mutex));
514 
515 	/*
516 	 * Get the header and config page.  reply contains the reply frame,
517 	 * which holds status info for the request.
518 	 */
519 	page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
520 	    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
521 	rval = mptsas_access_config_page(mpt,
522 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
523 	    MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
524 	    mptsas_raidphydsk_page_0_cb, &devhdl, &state);
525 
526 	/*
527 	 * Get the required information from the page.
528 	 */
529 	if (rval == DDI_SUCCESS) {
530 		for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
531 			/* find the correct position in the arrays */
532 			if (raidvol->m_disknum[i] == physdisknum)
533 				break;
534 		}
535 		raidvol->m_devhdl[i] = devhdl;
536 
537 		switch (state) {
538 			case MPI2_RAID_PD_STATE_OFFLINE:
539 				raidvol->m_diskstatus[i] =
540 				    RAID_DISKSTATUS_FAILED;
541 				break;
542 
543 			case MPI2_RAID_PD_STATE_HOT_SPARE:
544 			case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
545 			case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
546 				break;
547 
548 			case MPI2_RAID_PD_STATE_DEGRADED:
549 			case MPI2_RAID_PD_STATE_OPTIMAL:
550 			case MPI2_RAID_PD_STATE_REBUILDING:
551 			case MPI2_RAID_PD_STATE_ONLINE:
552 			default:
553 				raidvol->m_diskstatus[i] =
554 				    RAID_DISKSTATUS_GOOD;
555 				break;
556 		}
557 	}
558 
559 	return (rval);
560 }
561 
562 /*
563  * The only RAID Action needed throughout the driver is for System Shutdown.
564  * Since this is the only RAID Action and because this Action does not require
565  * waiting for a reply, make this a non-generic function.  If it turns out that
566  * other RAID Actions are required later, a generic function should be used.
567  */
568 void
569 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
570 {
571 	pMpi2RaidActionRequest_t	action;
572 	uint8_t				ir_active = FALSE;
573 	mptsas_slots_t			*slots = mpt->m_active;
574 	int				config, vol, action_flags = 0;
575 	mptsas_cmd_t			*cmd;
576 	struct scsi_pkt			*pkt;
577 	uint32_t			request_desc_low;
578 
579 	ASSERT(mutex_owned(&mpt->m_mutex));
580 
581 	/*
582 	 * Before doing the system shutdown RAID Action, make sure that the IOC
583 	 * supports IR and make sure there is a valid volume for the request.
584 	 */
585 	if (mpt->m_ir_capable) {
586 		for (config = 0; config < slots->m_num_raid_configs;
587 		    config++) {
588 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
589 				if (slots->m_raidconfig[config].m_raidvol[vol].
590 				    m_israid) {
591 					ir_active = TRUE;
592 					break;
593 				}
594 			}
595 		}
596 	}
597 	if (!ir_active) {
598 		return;
599 	}
600 
601 	/*
602 	 * Get a command from the pool.
603 	 */
604 	if (mptsas_request_from_pool(mpt, &cmd, &pkt) == -1) {
605 		mptsas_log(mpt, CE_NOTE, "command pool is full for RAID "
606 		    "action request");
607 		return;
608 	}
609 	action_flags |= MPTSAS_REQUEST_POOL_CMD;
610 
611 	bzero((caddr_t)cmd, sizeof (*cmd));
612 	bzero((caddr_t)pkt, scsi_pkt_size());
613 
614 	pkt->pkt_cdbp		= (opaque_t)&cmd->cmd_cdb[0];
615 	pkt->pkt_scbp		= (opaque_t)&cmd->cmd_scb;
616 	pkt->pkt_ha_private	= (opaque_t)cmd;
617 	pkt->pkt_flags		= (FLAG_NOINTR | FLAG_HEAD);
618 	pkt->pkt_time		= 5;
619 	cmd->cmd_pkt		= pkt;
620 	cmd->cmd_flags		= CFLAG_CMDIOC;
621 
622 	/*
623 	 * Send RAID Action.  We don't care what the reply is so just exit
624 	 * after sending the request.  This is just sent to the controller to
625 	 * keep the volume from having to resync the next time it starts.  If
626 	 * the request doesn't work for whatever reason, we're not going to
627 	 * bother wondering why.
628 	 */
629 	if (mptsas_save_cmd(mpt, cmd) == TRUE) {
630 		cmd->cmd_flags |= CFLAG_PREPARED;
631 		/*
632 		 * Form message for raid action
633 		 */
634 		action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
635 		    (mpt->m_req_frame_size * cmd->cmd_slot));
636 		bzero(action, mpt->m_req_frame_size);
637 		action->Function = MPI2_FUNCTION_RAID_ACTION;
638 		action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
639 
640 		/*
641 		 * Send request
642 		 */
643 		(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
644 		    DDI_DMA_SYNC_FORDEV);
645 		request_desc_low = (cmd->cmd_slot << 16) +
646 		    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
647 		MPTSAS_START_CMD(mpt, request_desc_low, 0);
648 
649 		/*
650 		 * Even though reply does not matter, wait no more than 5
651 		 * seconds here to get the reply just because we don't want to
652 		 * leave it hanging if it's coming.  Use the FW diag cv.
653 		 */
654 		(void) cv_reltimedwait(&mpt->m_fw_diag_cv, &mpt->m_mutex,
655 		    drv_usectohz(5 * MICROSEC), TR_CLOCK_TICK);
656 	}
657 
658 	/*
659 	 * Be sure to deallocate cmd before leaving.
660 	 */
661 	if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
662 		mptsas_remove_cmd(mpt, cmd);
663 		action_flags &= (~MPTSAS_REQUEST_POOL_CMD);
664 	}
665 	if (action_flags & MPTSAS_REQUEST_POOL_CMD)
666 		mptsas_return_to_pool(mpt, cmd);
667 
668 }
669 
670 int
671 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
672 {
673 	int		config, i, vol = (-1);
674 	mptsas_slots_t	*slots = mpt->m_active;
675 
676 	for (config = 0; config < slots->m_num_raid_configs; config++) {
677 		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
678 			if (slots->m_raidconfig[config].m_raidvol[i].
679 			    m_raidhandle == volid) {
680 				vol = i;
681 				break;
682 			}
683 		}
684 	}
685 
686 	if (vol < 0) {
687 		mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
688 		    "target.");
689 		return (-1);
690 	}
691 
692 	slots->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
693 	slots->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
694 	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
695 		slots->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
696 		slots->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
697 	}
698 
699 	return (0);
700 }
701