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 done:
468 return (rval);
469 }
470
471 static int
472 mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
473 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
474 va_list ap)
475 {
476 #ifndef __lock_lint
477 _NOTE(ARGUNUSED(ap))
478 #endif
479 pMpi2RaidPhysDiskPage0_t diskpage;
480 int rval = DDI_SUCCESS;
481 uint16_t *devhdl;
482 uint8_t *state;
483
484 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
485 return (DDI_FAILURE);
486
487 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
488 mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
489 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
490 iocstatus, iocloginfo);
491 rval = DDI_FAILURE;
492 return (rval);
493 }
494 devhdl = va_arg(ap, uint16_t *);
495 state = va_arg(ap, uint8_t *);
496 diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
497 *devhdl = ddi_get16(accessp, &diskpage->DevHandle);
498 *state = ddi_get8(accessp, &diskpage->PhysDiskState);
499 return (rval);
500 }
501
502 int
503 mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
504 uint8_t physdisknum)
505 {
506 int rval = DDI_SUCCESS, i;
507 uint8_t state;
508 uint16_t devhdl;
509 uint32_t page_address;
510
511 ASSERT(mutex_owned(&mpt->m_mutex));
512
513 /*
514 * Get the header and config page. reply contains the reply frame,
515 * which holds status info for the request.
516 */
517 page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
518 MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
519 rval = mptsas_access_config_page(mpt,
520 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
521 MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
522 mptsas_raidphydsk_page_0_cb, &devhdl, &state);
523
524 /*
525 * Get the required information from the page.
526 */
527 if (rval == DDI_SUCCESS) {
528 for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
529 /* find the correct position in the arrays */
530 if (raidvol->m_disknum[i] == physdisknum)
531 break;
532 }
533 raidvol->m_devhdl[i] = devhdl;
534
535 switch (state) {
536 case MPI2_RAID_PD_STATE_OFFLINE:
537 raidvol->m_diskstatus[i] =
538 RAID_DISKSTATUS_FAILED;
539 break;
540
541 case MPI2_RAID_PD_STATE_HOT_SPARE:
542 case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
543 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
544 break;
545
546 case MPI2_RAID_PD_STATE_DEGRADED:
547 case MPI2_RAID_PD_STATE_OPTIMAL:
548 case MPI2_RAID_PD_STATE_REBUILDING:
549 case MPI2_RAID_PD_STATE_ONLINE:
550 default:
551 raidvol->m_diskstatus[i] =
552 RAID_DISKSTATUS_GOOD;
553 break;
554 }
555 }
556
557 return (rval);
558 }
559
560 /*
561 * RAID Action for System Shutdown. This request uses the dedicated TM slot to
562 * avoid a call to mptsas_save_cmd. Since Solaris requires that the mutex is
563 * not held during the mptsas_quiesce function, this RAID action must not use
564 * the normal code path of requests and replies.
565 */
566 void
567 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
568 {
569 pMpi2RaidActionRequest_t action;
570 uint8_t ir_active = FALSE, reply_type;
571 uint8_t function, found_reply = FALSE;
572 uint16_t SMID, action_type;
573 mptsas_slots_t *slots = mpt->m_active;
574 int config, vol;
575 mptsas_cmd_t *cmd;
576 uint32_t request_desc_low, reply_addr;
577 int cnt;
578 pMpi2ReplyDescriptorsUnion_t reply_desc_union;
579 pMPI2DefaultReply_t reply;
580 pMpi2AddressReplyDescriptor_t address_reply;
581
582 /*
583 * Before doing the system shutdown RAID Action, make sure that the IOC
584 * supports IR and make sure there is a valid volume for the request.
585 */
586 if (mpt->m_ir_capable) {
587 for (config = 0; (config < mpt->m_num_raid_configs) &&
588 (!ir_active); config++) {
589 for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
590 if (mpt->m_raidconfig[config].m_raidvol[vol].
591 m_israid) {
592 ir_active = TRUE;
593 break;
594 }
595 }
596 }
597 }
598 if (!ir_active) {
599 return;
600 }
601
602 /*
603 * If TM slot is already being used (highly unlikely), show message and
604 * don't issue the RAID action.
605 */
606 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
607 mptsas_log(mpt, CE_WARN, "RAID Action slot in use. Cancelling"
608 " System Shutdown RAID Action.\n");
609 return;
610 }
611
612 /*
613 * Create the cmd and put it in the dedicated TM slot.
614 */
615 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
616 bzero((caddr_t)cmd, sizeof (*cmd));
617 cmd->cmd_pkt = NULL;
618 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
619 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
620
621 /*
622 * Form message for raid action.
623 */
624 action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
625 (mpt->m_req_frame_size * cmd->cmd_slot));
626 bzero(action, mpt->m_req_frame_size);
627 action->Function = MPI2_FUNCTION_RAID_ACTION;
628 action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
629
630 /*
631 * Send RAID Action.
632 */
633 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
634 DDI_DMA_SYNC_FORDEV);
635 request_desc_low = (cmd->cmd_slot << 16) +
636 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
637 MPTSAS_START_CMD(mpt, request_desc_low, 0);
638
639 /*
640 * Even though reply does not matter because the system is shutting
641 * down, wait no more than 5 seconds here to get the reply just because
642 * we don't want to leave it hanging if it's coming. Poll because
643 * interrupts are disabled when this function is called.
644 */
645 for (cnt = 0; cnt < 5000; cnt++) {
646 /*
647 * Check for a reply.
648 */
649 (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
650 DDI_DMA_SYNC_FORCPU);
651
652 reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
653 MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
654
655 if (ddi_get32(mpt->m_acc_post_queue_hdl,
656 &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
657 ddi_get32(mpt->m_acc_post_queue_hdl,
658 &reply_desc_union->Words.High) == 0xFFFFFFFF) {
659 drv_usecwait(1000);
660 continue;
661 }
662
663 /*
664 * There is a reply. If it's not an address reply, ignore it.
665 */
666 reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
667 &reply_desc_union->Default.ReplyFlags);
668 reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
669 if (reply_type != MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
670 goto clear_and_continue;
671 }
672
673 /*
674 * SMID must be the TM slot since that's what we're using for
675 * this RAID action. If not, ignore this reply.
676 */
677 address_reply =
678 (pMpi2AddressReplyDescriptor_t)reply_desc_union;
679 SMID = ddi_get16(mpt->m_acc_post_queue_hdl,
680 &address_reply->SMID);
681 if (SMID != MPTSAS_TM_SLOT(mpt)) {
682 goto clear_and_continue;
683 }
684
685 /*
686 * If reply frame is not in the proper range ignore it.
687 */
688 reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
689 &address_reply->ReplyFrameAddress);
690 if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
691 (reply_addr >= (mpt->m_reply_frame_dma_addr +
692 (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
693 ((reply_addr - mpt->m_reply_frame_dma_addr) %
694 mpt->m_reply_frame_size != 0)) {
695 goto clear_and_continue;
696 }
697
698 /*
699 * If not a RAID action reply ignore it.
700 */
701 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
702 DDI_DMA_SYNC_FORCPU);
703 reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame +
704 (reply_addr - mpt->m_reply_frame_dma_addr));
705 function = ddi_get8(mpt->m_acc_reply_frame_hdl,
706 &reply->Function);
707 if (function != MPI2_FUNCTION_RAID_ACTION) {
708 goto clear_and_continue;
709 }
710
711 /*
712 * Finally, make sure this is the System Shutdown RAID action.
713 * If not, ignore reply.
714 */
715 action_type = ddi_get16(mpt->m_acc_reply_frame_hdl,
716 &reply->FunctionDependent1);
717 if (action_type !=
718 MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
719 goto clear_and_continue;
720 }
721 found_reply = TRUE;
722
723 clear_and_continue:
724 /*
725 * Clear the reply descriptor for re-use and increment index.
726 */
727 ddi_put64(mpt->m_acc_post_queue_hdl,
728 &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index],
729 0xFFFFFFFFFFFFFFFF);
730 (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
731 DDI_DMA_SYNC_FORDEV);
732
733 /*
734 * Update the global reply index and keep looking for the
735 * reply if not found yet.
736 */
737 if (++mpt->m_post_index == mpt->m_post_queue_depth) {
738 mpt->m_post_index = 0;
739 }
740 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
741 mpt->m_post_index);
742 if (!found_reply) {
743 continue;
744 }
745
746 break;
747 }
748
749 /*
750 * clear the used slot as the last step.
751 */
752 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
753 }
754
755 int
756 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
757 {
758 int config, i = 0, vol = (-1);
759
760 for (config = 0; (config < mpt->m_num_raid_configs) && (vol != i);
761 config++) {
762 for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
763 if (mpt->m_raidconfig[config].m_raidvol[i].
764 m_raidhandle == volid) {
765 vol = i;
766 break;
767 }
768 }
769 }
770
771 if (vol < 0) {
772 mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
773 "target.");
774 return (-1);
775 }
776
777 mpt->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
778 mpt->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
779 for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
780 mpt->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
781 mpt->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
782 }
783
784 return (0);
785 }