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 }