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  */
26 
27 /*
28  * Copyright (c) 2000 to 2010, 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_t *, uint16_t,
95     uint64_t, uint32_t, mptsas_phymask_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 	m_raidconfig_t *raidconfig;
114 	uint64_t raidwwn;
115 	uint32_t native;
116 	mptsas_target_t	*ptgt;
117 	uint32_t configindex;
118 
119 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
120 		return (DDI_FAILURE);
121 	}
122 
123 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
124 		mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 "
125 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
126 		    iocstatus, iocloginfo);
127 		rval = DDI_FAILURE;
128 		return (rval);
129 	}
130 	confignum = va_arg(ap,  uint32_t *);
131 	configindex = va_arg(ap, uint32_t);
132 	raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp;
133 	/*
134 	 * Get all RAID configurations.
135 	 */
136 	etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT;
137 	etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT;
138 	etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT;
139 	etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT;
140 	/*
141 	 * Set up page address for next time through.
142 	 */
143 	*confignum =  ddi_get8(accessp,
144 	    &raidconfig_page0->ConfigNum);
145 
146 	/*
147 	 * Point to the right config in the structure.
148 	 * Increment the number of valid RAID configs.
149 	 */
150 	raidconfig = &mpt->m_raidconfig[configindex];
151 	mpt->m_num_raid_configs++;
152 
153 	/*
154 	 * Set the native flag if this is not a foreign
155 	 * configuration.
156 	 */
157 	native = ddi_get32(accessp, &raidconfig_page0->Flags);
158 	if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) {
159 		native = FALSE;
160 	} else {
161 		native = TRUE;
162 	}
163 	raidconfig->m_native = (uint8_t)native;
164 
165 	/*
166 	 * Get volume information for the volumes in the
167 	 * config.
168 	 */
169 	numelements = ddi_get8(accessp, &raidconfig_page0->NumElements);
170 	vol = 0;
171 	disk = 0;
172 	element = (pMpi2RaidConfig0ConfigElement_t)
173 	    &raidconfig_page0->ConfigElement;
174 
175 	for (i = 0; ((i < numelements) && native); i++, element++) {
176 		/*
177 		 * Get the element type.  Could be Volume,
178 		 * PhysDisk, Hot Spare, or Online Capacity
179 		 * Expansion PhysDisk.
180 		 */
181 		elementtype = ddi_get16(accessp, &element->ElementFlags);
182 		elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
183 
184 		/*
185 		 * For volumes, get the RAID settings and the
186 		 * WWID.
187 		 */
188 		if (elementtype == etype_vol) {
189 			voldevhandle = ddi_get16(accessp,
190 			    &element->VolDevHandle);
191 			raidconfig->m_raidvol[vol].m_israid = 1;
192 			raidconfig->m_raidvol[vol].
193 			    m_raidhandle = voldevhandle;
194 			/*
195 			 * Get the settings for the raid
196 			 * volume.  This includes the
197 			 * DevHandles for the disks making up
198 			 * the raid volume.
199 			 */
200 			if (mptsas_get_raid_settings(mpt,
201 			    &raidconfig->m_raidvol[vol]))
202 				continue;
203 
204 			/*
205 			 * Get the WWID of the RAID volume for
206 			 * SAS HBA
207 			 */
208 			if (mptsas_get_raid_wwid(mpt,
209 			    &raidconfig->m_raidvol[vol]))
210 				continue;
211 
212 			raidwwn = raidconfig->m_raidvol[vol].
213 			    m_raidwwid;
214 
215 			/*
216 			 * RAID uses phymask of 0.
217 			 */
218 			ptgt = mptsas_tgt_alloc(mpt,
219 			    voldevhandle, raidwwn, 0, 0, 0);
220 
221 			raidconfig->m_raidvol[vol].m_raidtgt =
222 			    ptgt;
223 
224 			/*
225 			 * Increment volume index within this
226 			 * raid config.
227 			 */
228 			vol++;
229 		} else if ((elementtype == etype_pd) ||
230 		    (elementtype == etype_hs) ||
231 		    (elementtype == etype_oce)) {
232 			/*
233 			 * For all other element types, put
234 			 * their DevHandles in the phys disk
235 			 * list of the config.  These are all
236 			 * some variation of a Phys Disk and
237 			 * this list is used to keep these
238 			 * disks from going online.
239 			 */
240 			raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp,
241 			    &element->PhysDiskDevHandle);
242 
243 			/*
244 			 * Increment disk index within this
245 			 * raid config.
246 			 */
247 			disk++;
248 		}
249 	}
250 
251 	return (rval);
252 }
253 
254 int
255 mptsas_get_raid_info(mptsas_t *mpt)
256 {
257 	int rval = DDI_SUCCESS;
258 	uint32_t confignum, pageaddress;
259 	uint8_t configindex;
260 
261 	ASSERT(mutex_owned(&mpt->m_mutex));
262 
263 	/*
264 	 * Clear all RAID info before starting.
265 	 */
266 	bzero(mpt->m_raidconfig, sizeof (mpt->m_raidconfig));
267 	mpt->m_num_raid_configs = 0;
268 
269 	configindex = 0;
270 	confignum = 0xff;
271 	pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum;
272 	while (rval == DDI_SUCCESS) {
273 		/*
274 		 * Get the header and config page.  reply contains the reply
275 		 * frame, which holds status info for the request.
276 		 */
277 		rval = mptsas_access_config_page(mpt,
278 		    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
279 		    MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress,
280 		    mptsas_raidconf_page_0_cb, &confignum, configindex);
281 		configindex++;
282 		pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM |
283 		    confignum;
284 	}
285 
286 	return (rval);
287 }
288 
289 static int
290 mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
291     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
292     va_list ap)
293 {
294 #ifndef __lock_lint
295 	_NOTE(ARGUNUSED(ap))
296 #endif
297 	pMpi2RaidVolPage0_t raidpage;
298 	int rval = DDI_SUCCESS, i;
299 	mptsas_raidvol_t *raidvol;
300 	uint8_t	numdisks, volstate, voltype, physdisknum;
301 	uint32_t volsetting;
302 	uint32_t statusflags, resync_flag;
303 
304 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
305 		return (DDI_FAILURE);
306 
307 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
308 		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb "
309 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
310 		    iocstatus, iocloginfo);
311 		rval = DDI_FAILURE;
312 		return (rval);
313 	}
314 
315 	raidvol = va_arg(ap,  mptsas_raidvol_t *);
316 
317 	raidpage = (pMpi2RaidVolPage0_t)page_memp;
318 	volstate = ddi_get8(accessp, &raidpage->VolumeState);
319 	volsetting = ddi_get32(accessp,
320 	    (uint32_t *)(void *)&raidpage->VolumeSettings);
321 	statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags);
322 	voltype = ddi_get8(accessp, &raidpage->VolumeType);
323 
324 	raidvol->m_state = volstate;
325 	raidvol->m_statusflags = statusflags;
326 	/*
327 	 * Volume size is not used right now. Set to 0.
328 	 */
329 	raidvol->m_raidsize = 0;
330 	raidvol->m_settings = volsetting;
331 	raidvol->m_raidlevel = voltype;
332 
333 	if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) {
334 		mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n",
335 		    raidvol->m_raidhandle);
336 	}
337 
338 	if (statusflags &
339 	    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
340 		mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n",
341 		    raidvol->m_raidhandle);
342 	}
343 
344 	resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
345 	switch (volstate) {
346 	case MPI2_RAID_VOL_STATE_OPTIMAL:
347 		mptsas_log(mpt, CE_NOTE, "?Volume %d is "
348 		    "optimal\n", raidvol->m_raidhandle);
349 		break;
350 	case MPI2_RAID_VOL_STATE_DEGRADED:
351 		if ((statusflags & resync_flag) == 0) {
352 			mptsas_log(mpt, CE_WARN, "Volume %d "
353 			    "is degraded\n",
354 			    raidvol->m_raidhandle);
355 		}
356 		break;
357 	case MPI2_RAID_VOL_STATE_FAILED:
358 		mptsas_log(mpt, CE_WARN, "Volume %d is "
359 		    "failed\n", raidvol->m_raidhandle);
360 		break;
361 	case MPI2_RAID_VOL_STATE_MISSING:
362 		mptsas_log(mpt, CE_WARN, "Volume %d is "
363 		    "missing\n", raidvol->m_raidhandle);
364 		break;
365 	default:
366 		break;
367 	}
368 	numdisks = raidpage->NumPhysDisks;
369 	raidvol->m_ndisks = numdisks;
370 	for (i = 0; i < numdisks; i++) {
371 		physdisknum = raidpage->PhysDisk[i].PhysDiskNum;
372 		raidvol->m_disknum[i] = physdisknum;
373 		if (mptsas_get_physdisk_settings(mpt, raidvol,
374 		    physdisknum))
375 			break;
376 	}
377 	return (rval);
378 }
379 
380 int
381 mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
382 {
383 	int rval = DDI_SUCCESS;
384 	uint32_t page_address;
385 
386 	ASSERT(mutex_owned(&mpt->m_mutex));
387 
388 	/*
389 	 * Get the header and config page.  reply contains the reply frame,
390 	 * which holds status info for the request.
391 	 */
392 	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
393 	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
394 	rval = mptsas_access_config_page(mpt,
395 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
396 	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address,
397 	    mptsas_raidvol_page_0_cb, raidvol);
398 
399 	return (rval);
400 }
401 
402 static int
403 mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
404     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
405     va_list ap)
406 {
407 #ifndef __lock_lint
408 	_NOTE(ARGUNUSED(ap))
409 #endif
410 	pMpi2RaidVolPage1_t	raidpage;
411 	int			rval = DDI_SUCCESS, i;
412 	uint8_t			*sas_addr = NULL;
413 	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
414 	uint64_t		*sas_wwn;
415 
416 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
417 		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb "
418 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
419 		    iocstatus, iocloginfo);
420 		rval = DDI_FAILURE;
421 		return (rval);
422 	}
423 	sas_wwn = va_arg(ap, uint64_t *);
424 
425 	raidpage = (pMpi2RaidVolPage1_t)page_memp;
426 	sas_addr = (uint8_t *)(&raidpage->WWID);
427 	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
428 		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
429 	}
430 	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
431 	*sas_wwn = LE_64(*sas_wwn);
432 	return (rval);
433 }
434 
435 static int
436 mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
437 {
438 	int rval = DDI_SUCCESS;
439 	uint32_t page_address;
440 	uint64_t sas_wwn;
441 
442 	ASSERT(mutex_owned(&mpt->m_mutex));
443 
444 	/*
445 	 * Get the header and config page.  reply contains the reply frame,
446 	 * which holds status info for the request.
447 	 */
448 	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
449 	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
450 	rval = mptsas_access_config_page(mpt,
451 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
452 	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address,
453 	    mptsas_raidvol_page_1_cb, &sas_wwn);
454 
455 	/*
456 	 * Get the required information from the page.
457 	 */
458 	if (rval == DDI_SUCCESS) {
459 
460 		/*
461 		 * replace top nibble of WWID of RAID to '3' for OBP
462 		 */
463 		sas_wwn = MPTSAS_RAID_WWID(sas_wwn);
464 		raidvol->m_raidwwid = sas_wwn;
465 	}
466 
467 	return (rval);
468 }
469 
470 static int
471 mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
472     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
473     va_list ap)
474 {
475 #ifndef __lock_lint
476 	_NOTE(ARGUNUSED(ap))
477 #endif
478 	pMpi2RaidPhysDiskPage0_t	diskpage;
479 	int			rval = DDI_SUCCESS;
480 	uint16_t		*devhdl;
481 	uint8_t			*state;
482 
483 	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
484 		return (DDI_FAILURE);
485 
486 	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
487 		mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
488 		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
489 		    iocstatus, iocloginfo);
490 		rval = DDI_FAILURE;
491 		return (rval);
492 	}
493 	devhdl = va_arg(ap, uint16_t *);
494 	state = va_arg(ap, uint8_t *);
495 	diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
496 	*devhdl = ddi_get16(accessp, &diskpage->DevHandle);
497 	*state = ddi_get8(accessp, &diskpage->PhysDiskState);
498 	return (rval);
499 }
500 
501 int
502 mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
503     uint8_t physdisknum)
504 {
505 	int			rval = DDI_SUCCESS, i;
506 	uint8_t			state;
507 	uint16_t		devhdl;
508 	uint32_t		page_address;
509 
510 	ASSERT(mutex_owned(&mpt->m_mutex));
511 
512 	/*
513 	 * Get the header and config page.  reply contains the reply frame,
514 	 * which holds status info for the request.
515 	 */
516 	page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
517 	    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
518 	rval = mptsas_access_config_page(mpt,
519 	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
520 	    MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
521 	    mptsas_raidphydsk_page_0_cb, &devhdl, &state);
522 
523 	/*
524 	 * Get the required information from the page.
525 	 */
526 	if (rval == DDI_SUCCESS) {
527 		for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
528 			/* find the correct position in the arrays */
529 			if (raidvol->m_disknum[i] == physdisknum)
530 				break;
531 		}
532 		raidvol->m_devhdl[i] = devhdl;
533 
534 		switch (state) {
535 			case MPI2_RAID_PD_STATE_OFFLINE:
536 				raidvol->m_diskstatus[i] =
537 				    RAID_DISKSTATUS_FAILED;
538 				break;
539 
540 			case MPI2_RAID_PD_STATE_HOT_SPARE:
541 			case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
542 			case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
543 				break;
544 
545 			case MPI2_RAID_PD_STATE_DEGRADED:
546 			case MPI2_RAID_PD_STATE_OPTIMAL:
547 			case MPI2_RAID_PD_STATE_REBUILDING:
548 			case MPI2_RAID_PD_STATE_ONLINE:
549 			default:
550 				raidvol->m_diskstatus[i] =
551 				    RAID_DISKSTATUS_GOOD;
552 				break;
553 		}
554 	}
555 
556 	return (rval);
557 }
558 
559 /*
560  * RAID Action for System Shutdown. This request uses the dedicated TM slot to
561  * avoid a call to mptsas_save_cmd.  Since Solaris requires that the mutex is
562  * not held during the mptsas_quiesce function, this RAID action must not use
563  * the normal code path of requests and replies.
564  */
565 void
566 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
567 {
568 	pMpi2RaidActionRequest_t	action;
569 	uint8_t				ir_active = FALSE, reply_type;
570 	uint8_t				function, found_reply = FALSE;
571 	uint16_t			SMID, action_type;
572 	mptsas_slots_t			*slots = mpt->m_active;
573 	int				config, vol;
574 	mptsas_cmd_t			*cmd;
575 	uint32_t			request_desc_low, reply_addr;
576 	int				cnt;
577 	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
578 	pMPI2DefaultReply_t		reply;
579 	pMpi2AddressReplyDescriptor_t	address_reply;
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 < mpt->m_num_raid_configs) &&
587 		    (!ir_active); config++) {
588 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
589 				if (mpt->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 	 * If TM slot is already being used (highly unlikely), show message and
603 	 * don't issue the RAID action.
604 	 */
605 	if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
606 		mptsas_log(mpt, CE_WARN, "RAID Action slot in use.  Cancelling"
607 		    " System Shutdown RAID Action.\n");
608 		return;
609 	}
610 
611 	/*
612 	 * Create the cmd and put it in the dedicated TM slot.
613 	 */
614 	cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
615 	bzero((caddr_t)cmd, sizeof (*cmd));
616 	cmd->cmd_pkt = NULL;
617 	cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
618 	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
619 
620 	/*
621 	 * Form message for raid action.
622 	 */
623 	action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
624 	    (mpt->m_req_frame_size * cmd->cmd_slot));
625 	bzero(action, mpt->m_req_frame_size);
626 	action->Function = MPI2_FUNCTION_RAID_ACTION;
627 	action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
628 
629 	/*
630 	 * Send RAID Action.
631 	 */
632 	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
633 	    DDI_DMA_SYNC_FORDEV);
634 	request_desc_low = (cmd->cmd_slot << 16) +
635 	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
636 	MPTSAS_START_CMD(mpt, request_desc_low, 0);
637 
638 	/*
639 	 * Even though reply does not matter because the system is shutting
640 	 * down, wait no more than 5 seconds here to get the reply just because
641 	 * we don't want to leave it hanging if it's coming.  Poll because
642 	 * interrupts are disabled when this function is called.
643 	 */
644 	for (cnt = 0; cnt < 5000; cnt++) {
645 		/*
646 		 * Check for a reply.
647 		 */
648 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
649 		    DDI_DMA_SYNC_FORCPU);
650 
651 		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
652 		    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
653 
654 		if (ddi_get32(mpt->m_acc_post_queue_hdl,
655 		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
656 		    ddi_get32(mpt->m_acc_post_queue_hdl,
657 		    &reply_desc_union->Words.High) == 0xFFFFFFFF) {
658 			drv_usecwait(1000);
659 			continue;
660 		}
661 
662 		/*
663 		 * There is a reply.  If it's not an address reply, ignore it.
664 		 */
665 		reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
666 		    &reply_desc_union->Default.ReplyFlags);
667 		reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
668 		if (reply_type != MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
669 			goto clear_and_continue;
670 		}
671 
672 		/*
673 		 * SMID must be the TM slot since that's what we're using for
674 		 * this RAID action.  If not, ignore this reply.
675 		 */
676 		address_reply =
677 		    (pMpi2AddressReplyDescriptor_t)reply_desc_union;
678 		SMID = ddi_get16(mpt->m_acc_post_queue_hdl,
679 		    &address_reply->SMID);
680 		if (SMID != MPTSAS_TM_SLOT(mpt)) {
681 			goto clear_and_continue;
682 		}
683 
684 		/*
685 		 * If reply frame is not in the proper range ignore it.
686 		 */
687 		reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
688 		    &address_reply->ReplyFrameAddress);
689 		if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
690 		    (reply_addr >= (mpt->m_reply_frame_dma_addr +
691 		    (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
692 		    ((reply_addr - mpt->m_reply_frame_dma_addr) %
693 		    mpt->m_reply_frame_size != 0)) {
694 			goto clear_and_continue;
695 		}
696 
697 		/*
698 		 * If not a RAID action reply ignore it.
699 		 */
700 		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
701 		    DDI_DMA_SYNC_FORCPU);
702 		reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame +
703 		    (reply_addr - mpt->m_reply_frame_dma_addr));
704 		function = ddi_get8(mpt->m_acc_reply_frame_hdl,
705 		    &reply->Function);
706 		if (function != MPI2_FUNCTION_RAID_ACTION) {
707 			goto clear_and_continue;
708 		}
709 
710 		/*
711 		 * Finally, make sure this is the System Shutdown RAID action.
712 		 * If not, ignore reply.
713 		 */
714 		action_type = ddi_get16(mpt->m_acc_reply_frame_hdl,
715 		    &reply->FunctionDependent1);
716 		if (action_type !=
717 		    MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
718 			goto clear_and_continue;
719 		}
720 		found_reply = TRUE;
721 
722 clear_and_continue:
723 		/*
724 		 * Clear the reply descriptor for re-use and increment index.
725 		 */
726 		ddi_put64(mpt->m_acc_post_queue_hdl,
727 		    &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index],
728 		    0xFFFFFFFFFFFFFFFF);
729 		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
730 		    DDI_DMA_SYNC_FORDEV);
731 
732 		/*
733 		 * Update the global reply index and keep looking for the
734 		 * reply if not found yet.
735 		 */
736 		if (++mpt->m_post_index == mpt->m_post_queue_depth) {
737 			mpt->m_post_index = 0;
738 		}
739 		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
740 		    mpt->m_post_index);
741 		if (!found_reply) {
742 			continue;
743 		}
744 
745 		break;
746 	}
747 
748 	/*
749 	 * clear the used slot as the last step.
750 	 */
751 	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
752 }
753 
754 int
755 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
756 {
757 	int		config, i = 0, vol = (-1);
758 
759 	for (config = 0; (config < mpt->m_num_raid_configs) && (vol != i);
760 	    config++) {
761 		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
762 			if (mpt->m_raidconfig[config].m_raidvol[i].
763 			    m_raidhandle == volid) {
764 				vol = i;
765 				break;
766 			}
767 		}
768 	}
769 
770 	if (vol < 0) {
771 		mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
772 		    "target.");
773 		return (-1);
774 	}
775 
776 	mpt->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
777 	mpt->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
778 	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
779 		mpt->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
780 		mpt->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
781 	}
782 
783 	return (0);
784 }
785