1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  26  */
  27 
  28 /*
  29  * Copyright (c) 2000 to 2010, LSI Corporation.
  30  * All rights reserved.
  31  *
  32  * Redistribution and use in source and binary forms of all code within
  33  * this file that is exclusively owned by LSI, with or without
  34  * modification, is permitted provided that, in addition to the CDDL 1.0
  35  * License requirements, the following conditions are met:
  36  *
  37  *    Neither the name of the author nor the names of its contributors may be
  38  *    used to endorse or promote products derived from this software without
  39  *    specific prior written permission.
  40  *
  41  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  42  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  43  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  44  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  45  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  47  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  48  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  49  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  52  * DAMAGE.
  53  */
  54 
  55 /*
  56  * mptsas_raid - This file contains all the RAID related functions for the
  57  * MPT interface.
  58  */
  59 
  60 #if defined(lint) || defined(DEBUG)
  61 #define MPTSAS_DEBUG
  62 #endif
  63 
  64 #define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX        2
  65 
  66 /*
  67  * standard header files
  68  */
  69 #include <sys/note.h>
  70 #include <sys/scsi/scsi.h>
  71 #include <sys/byteorder.h>
  72 #include <sys/raidioctl.h>
  73 
  74 #pragma pack(1)
  75 
  76 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h>
  77 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h>
  78 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h>
  79 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h>
  80 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h>
  81 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h>
  82 #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h>
  83 
  84 #pragma pack()
  85 
  86 /*
  87  * private header files.
  88  */
  89 #include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h>
  90 
  91 static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
  92 
  93 extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
  94 extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
  95 extern mptsas_target_t *mptsas_tgt_alloc(mptsas_t *, uint16_t,
  96     uint64_t, uint32_t, mptsas_phymask_t, uint8_t);
  97 
  98 static int
  99 mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
 100     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
 101     va_list ap)
 102 {
 103 #ifndef __lock_lint
 104         _NOTE(ARGUNUSED(ap))
 105 #endif
 106         pMpi2RaidConfigurationPage0_t   raidconfig_page0;
 107         pMpi2RaidConfig0ConfigElement_t element;
 108         uint32_t *confignum;
 109         int rval = DDI_SUCCESS, i;
 110         uint8_t numelements, vol, disk;
 111         uint16_t elementtype, voldevhandle;
 112         uint16_t etype_vol, etype_pd, etype_hs;
 113         uint16_t etype_oce;
 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 = &mpt->m_raidconfig[configindex];
 152         mpt->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) && native); 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(mpt,
 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 
 262         ASSERT(mutex_owned(&mpt->m_mutex));
 263 
 264         /*
 265          * Clear all RAID info before starting.
 266          */
 267         bzero(mpt->m_raidconfig, sizeof (mpt->m_raidconfig));
 268         mpt->m_num_raid_configs = 0;
 269 
 270         configindex = 0;
 271         confignum = 0xff;
 272         pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum;
 273         while (rval == DDI_SUCCESS) {
 274                 /*
 275                  * Get the header and config page.  reply contains the reply
 276                  * frame, which holds status info for the request.
 277                  */
 278                 rval = mptsas_access_config_page(mpt,
 279                     MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
 280                     MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress,
 281                     mptsas_raidconf_page_0_cb, &confignum, configindex);
 282                 configindex++;
 283                 pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM |
 284                     confignum;
 285         }
 286 
 287         return (rval);
 288 }
 289 
 290 static int
 291 mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
 292     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
 293     va_list ap)
 294 {
 295 #ifndef __lock_lint
 296         _NOTE(ARGUNUSED(ap))
 297 #endif
 298         pMpi2RaidVolPage0_t raidpage;
 299         int rval = DDI_SUCCESS, i;
 300         mptsas_raidvol_t *raidvol;
 301         uint8_t numdisks, volstate, voltype, physdisknum;
 302         uint32_t volsetting;
 303         uint32_t statusflags, resync_flag;
 304 
 305         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 306                 return (DDI_FAILURE);
 307 
 308         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
 309                 mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb "
 310                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
 311                     iocstatus, iocloginfo);
 312                 rval = DDI_FAILURE;
 313                 return (rval);
 314         }
 315 
 316         raidvol = va_arg(ap,  mptsas_raidvol_t *);
 317 
 318         raidpage = (pMpi2RaidVolPage0_t)page_memp;
 319         volstate = ddi_get8(accessp, &raidpage->VolumeState);
 320         volsetting = ddi_get32(accessp,
 321             (uint32_t *)(void *)&raidpage->VolumeSettings);
 322         statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags);
 323         voltype = ddi_get8(accessp, &raidpage->VolumeType);
 324 
 325         raidvol->m_state = volstate;
 326         raidvol->m_statusflags = statusflags;
 327         /*
 328          * Volume size is not used right now. Set to 0.
 329          */
 330         raidvol->m_raidsize = 0;
 331         raidvol->m_settings = volsetting;
 332         raidvol->m_raidlevel = voltype;
 333 
 334         if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) {
 335                 mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n",
 336                     raidvol->m_raidhandle);
 337         }
 338 
 339         if (statusflags &
 340             MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
 341                 mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n",
 342                     raidvol->m_raidhandle);
 343         }
 344 
 345         resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
 346         switch (volstate) {
 347         case MPI2_RAID_VOL_STATE_OPTIMAL:
 348                 mptsas_log(mpt, CE_NOTE, "?Volume %d is "
 349                     "optimal\n", raidvol->m_raidhandle);
 350                 break;
 351         case MPI2_RAID_VOL_STATE_DEGRADED:
 352                 if ((statusflags & resync_flag) == 0) {
 353                         mptsas_log(mpt, CE_WARN, "Volume %d "
 354                             "is degraded\n",
 355                             raidvol->m_raidhandle);
 356                 }
 357                 break;
 358         case MPI2_RAID_VOL_STATE_FAILED:
 359                 mptsas_log(mpt, CE_WARN, "Volume %d is "
 360                     "failed\n", raidvol->m_raidhandle);
 361                 break;
 362         case MPI2_RAID_VOL_STATE_MISSING:
 363                 mptsas_log(mpt, CE_WARN, "Volume %d is "
 364                     "missing\n", raidvol->m_raidhandle);
 365                 break;
 366         default:
 367                 break;
 368         }
 369         numdisks = raidpage->NumPhysDisks;
 370         raidvol->m_ndisks = numdisks;
 371         for (i = 0; i < numdisks; i++) {
 372                 physdisknum = raidpage->PhysDisk[i].PhysDiskNum;
 373                 raidvol->m_disknum[i] = physdisknum;
 374                 if (mptsas_get_physdisk_settings(mpt, raidvol,
 375                     physdisknum))
 376                         break;
 377         }
 378         return (rval);
 379 }
 380 
 381 int
 382 mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
 383 {
 384         int rval = DDI_SUCCESS;
 385         uint32_t page_address;
 386 
 387         ASSERT(mutex_owned(&mpt->m_mutex));
 388 
 389         /*
 390          * Get the header and config page.  reply contains the reply frame,
 391          * which holds status info for the request.
 392          */
 393         page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
 394             MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
 395         rval = mptsas_access_config_page(mpt,
 396             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
 397             MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address,
 398             mptsas_raidvol_page_0_cb, raidvol);
 399 
 400         return (rval);
 401 }
 402 
 403 static int
 404 mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
 405     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
 406     va_list ap)
 407 {
 408 #ifndef __lock_lint
 409         _NOTE(ARGUNUSED(ap))
 410 #endif
 411         pMpi2RaidVolPage1_t     raidpage;
 412         int                     rval = DDI_SUCCESS, i;
 413         uint8_t                 *sas_addr = NULL;
 414         uint8_t                 tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
 415         uint64_t                *sas_wwn;
 416 
 417         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
 418                 mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb "
 419                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
 420                     iocstatus, iocloginfo);
 421                 rval = DDI_FAILURE;
 422                 return (rval);
 423         }
 424         sas_wwn = va_arg(ap, uint64_t *);
 425 
 426         raidpage = (pMpi2RaidVolPage1_t)page_memp;
 427         sas_addr = (uint8_t *)(&raidpage->WWID);
 428         for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
 429                 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
 430         }
 431         bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
 432         *sas_wwn = LE_64(*sas_wwn);
 433         return (rval);
 434 }
 435 
 436 static int
 437 mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
 438 {
 439         int rval = DDI_SUCCESS;
 440         uint32_t page_address;
 441         uint64_t sas_wwn;
 442 
 443         ASSERT(mutex_owned(&mpt->m_mutex));
 444 
 445         /*
 446          * Get the header and config page.  reply contains the reply frame,
 447          * which holds status info for the request.
 448          */
 449         page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
 450             MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
 451         rval = mptsas_access_config_page(mpt,
 452             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
 453             MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address,
 454             mptsas_raidvol_page_1_cb, &sas_wwn);
 455 
 456         /*
 457          * Get the required information from the page.
 458          */
 459         if (rval == DDI_SUCCESS) {
 460 
 461                 /*
 462                  * replace top nibble of WWID of RAID to '3' for OBP
 463                  */
 464                 sas_wwn = MPTSAS_RAID_WWID(sas_wwn);
 465                 raidvol->m_raidwwid = sas_wwn;
 466         }
 467 
 468 done:
 469         return (rval);
 470 }
 471 
 472 static int
 473 mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
 474     ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
 475     va_list ap)
 476 {
 477 #ifndef __lock_lint
 478         _NOTE(ARGUNUSED(ap))
 479 #endif
 480         pMpi2RaidPhysDiskPage0_t        diskpage;
 481         int                     rval = DDI_SUCCESS;
 482         uint16_t                *devhdl;
 483         uint8_t                 *state;
 484 
 485         if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 486                 return (DDI_FAILURE);
 487 
 488         if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
 489                 mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
 490                     "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
 491                     iocstatus, iocloginfo);
 492                 rval = DDI_FAILURE;
 493                 return (rval);
 494         }
 495         devhdl = va_arg(ap, uint16_t *);
 496         state = va_arg(ap, uint8_t *);
 497         diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
 498         *devhdl = ddi_get16(accessp, &diskpage->DevHandle);
 499         *state = ddi_get8(accessp, &diskpage->PhysDiskState);
 500         return (rval);
 501 }
 502 
 503 int
 504 mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
 505     uint8_t physdisknum)
 506 {
 507         int                     rval = DDI_SUCCESS, i;
 508         uint8_t                 state;
 509         uint16_t                devhdl;
 510         uint32_t                page_address;
 511 
 512         ASSERT(mutex_owned(&mpt->m_mutex));
 513 
 514         /*
 515          * Get the header and config page.  reply contains the reply frame,
 516          * which holds status info for the request.
 517          */
 518         page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
 519             MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
 520         rval = mptsas_access_config_page(mpt,
 521             MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
 522             MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
 523             mptsas_raidphydsk_page_0_cb, &devhdl, &state);
 524 
 525         /*
 526          * Get the required information from the page.
 527          */
 528         if (rval == DDI_SUCCESS) {
 529                 for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
 530                         /* find the correct position in the arrays */
 531                         if (raidvol->m_disknum[i] == physdisknum)
 532                                 break;
 533                 }
 534                 raidvol->m_devhdl[i] = devhdl;
 535 
 536                 switch (state) {
 537                         case MPI2_RAID_PD_STATE_OFFLINE:
 538                                 raidvol->m_diskstatus[i] =
 539                                     RAID_DISKSTATUS_FAILED;
 540                                 break;
 541 
 542                         case MPI2_RAID_PD_STATE_HOT_SPARE:
 543                         case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
 544                         case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
 545                                 break;
 546 
 547                         case MPI2_RAID_PD_STATE_DEGRADED:
 548                         case MPI2_RAID_PD_STATE_OPTIMAL:
 549                         case MPI2_RAID_PD_STATE_REBUILDING:
 550                         case MPI2_RAID_PD_STATE_ONLINE:
 551                         default:
 552                                 raidvol->m_diskstatus[i] =
 553                                     RAID_DISKSTATUS_GOOD;
 554                                 break;
 555                 }
 556         }
 557 
 558         return (rval);
 559 }
 560 
 561 /*
 562  * RAID Action for System Shutdown. This request uses the dedicated TM slot to
 563  * avoid a call to mptsas_save_cmd.  Since Solaris requires that the mutex is
 564  * not held during the mptsas_quiesce function, this RAID action must not use
 565  * the normal code path of requests and replies.
 566  */
 567 void
 568 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
 569 {
 570         mptsas_reply_pqueue_t           *rpqp;
 571         pMpi2RaidActionRequest_t        action;
 572         uint8_t                         ir_active = FALSE, reply_type;
 573         uint8_t                         function, found_reply = FALSE;
 574         uint16_t                        SMID, action_type;
 575         mptsas_slots_t                  *slots = mpt->m_active;
 576         int                             config, vol;
 577         mptsas_cmd_t                    *cmd;
 578         uint32_t                        reply_addr;
 579         uint64_t                        request_desc;
 580         int                             cnt;
 581         pMpi2ReplyDescriptorsUnion_t    reply_desc_union;
 582         pMPI2DefaultReply_t             reply;
 583         pMpi2AddressReplyDescriptor_t   address_reply;
 584 
 585         /*
 586          * Before doing the system shutdown RAID Action, make sure that the IOC
 587          * supports IR and make sure there is a valid volume for the request.
 588          */
 589         if (mpt->m_ir_capable) {
 590                 for (config = 0; (config < mpt->m_num_raid_configs) &&
 591                     (!ir_active); config++) {
 592                         for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
 593                                 if (mpt->m_raidconfig[config].m_raidvol[vol].
 594                                     m_israid) {
 595                                         ir_active = TRUE;
 596                                         break;
 597                                 }
 598                         }
 599                 }
 600         }
 601         if (!ir_active) {
 602                 return;
 603         }
 604 
 605         /*
 606          * If TM slot is already being used (highly unlikely), show message and
 607          * don't issue the RAID action.
 608          */
 609         if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
 610                 mptsas_log(mpt, CE_WARN, "RAID Action slot in use.  Cancelling"
 611                     " System Shutdown RAID Action.\n");
 612                 return;
 613         }
 614 
 615         /*
 616          * Create the cmd and put it in the dedicated TM slot.
 617          */
 618         cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
 619         bzero((caddr_t)cmd, sizeof (*cmd));
 620         cmd->cmd_pkt = NULL;
 621         cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
 622         slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
 623 
 624         /*
 625          * Form message for raid action.
 626          */
 627         action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
 628             (mpt->m_req_frame_size * cmd->cmd_slot));
 629         bzero(action, mpt->m_req_frame_size);
 630         action->Function = MPI2_FUNCTION_RAID_ACTION;
 631         action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
 632 
 633         /*
 634          * Send RAID Action.
 635          * Defaults to MSIxIndex of 0, so check reply q 0 below.
 636          */
 637         (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
 638             DDI_DMA_SYNC_FORDEV);
 639         request_desc = (cmd->cmd_slot << 16) +
 640             MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 641         MPTSAS_START_CMD(mpt, request_desc);
 642 
 643         /*
 644          * Even though reply does not matter because the system is shutting
 645          * down, wait no more than 5 seconds here to get the reply just because
 646          * we don't want to leave it hanging if it's coming.  Poll because
 647          * interrupts are disabled when this function is called.
 648          */
 649         rpqp = mpt->m_rep_post_queues;
 650         for (cnt = 0; cnt < 5000; cnt++) {
 651                 /*
 652                  * Check for a reply.
 653                  */
 654                 (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
 655                     DDI_DMA_SYNC_FORCPU);
 656 
 657                 reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
 658                     MPTSAS_GET_NEXT_REPLY(rpqp, rpqp->rpq_index);
 659 
 660                 if (ddi_get32(mpt->m_acc_post_queue_hdl,
 661                     &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
 662                     ddi_get32(mpt->m_acc_post_queue_hdl,
 663                     &reply_desc_union->Words.High) == 0xFFFFFFFF) {
 664                         drv_usecwait(1000);
 665                         continue;
 666                 }
 667 
 668                 /*
 669                  * There is a reply.  If it's not an address reply, ignore it.
 670                  */
 671                 reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
 672                     &reply_desc_union->Default.ReplyFlags);
 673                 reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
 674                 if (reply_type != MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
 675                         goto clear_and_continue;
 676                 }
 677 
 678                 /*
 679                  * SMID must be the TM slot since that's what we're using for
 680                  * this RAID action.  If not, ignore this reply.
 681                  */
 682                 address_reply =
 683                     (pMpi2AddressReplyDescriptor_t)reply_desc_union;
 684                 SMID = ddi_get16(mpt->m_acc_post_queue_hdl,
 685                     &address_reply->SMID);
 686                 if (SMID != MPTSAS_TM_SLOT(mpt)) {
 687                         goto clear_and_continue;
 688                 }
 689 
 690                 /*
 691                  * If reply frame is not in the proper range ignore it.
 692                  */
 693                 reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
 694                     &address_reply->ReplyFrameAddress);
 695                 if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
 696                     (reply_addr >= (mpt->m_reply_frame_dma_addr +
 697                     (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
 698                     ((reply_addr - mpt->m_reply_frame_dma_addr) %
 699                     mpt->m_reply_frame_size != 0)) {
 700                         goto clear_and_continue;
 701                 }
 702 
 703                 /*
 704                  * If not a RAID action reply ignore it.
 705                  */
 706                 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
 707                     DDI_DMA_SYNC_FORCPU);
 708                 reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame +
 709                     (reply_addr - mpt->m_reply_frame_dma_addr));
 710                 function = ddi_get8(mpt->m_acc_reply_frame_hdl,
 711                     &reply->Function);
 712                 if (function != MPI2_FUNCTION_RAID_ACTION) {
 713                         goto clear_and_continue;
 714                 }
 715 
 716                 /*
 717                  * Finally, make sure this is the System Shutdown RAID action.
 718                  * If not, ignore reply.
 719                  */
 720                 action_type = ddi_get16(mpt->m_acc_reply_frame_hdl,
 721                     &reply->FunctionDependent1);
 722                 if (action_type !=
 723                     MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
 724                         goto clear_and_continue;
 725                 }
 726                 found_reply = TRUE;
 727 
 728 clear_and_continue:
 729                 /*
 730                  * Clear the reply descriptor for re-use and increment index.
 731                  */
 732                 ddi_put64(mpt->m_acc_post_queue_hdl,
 733                     &((uint64_t *)(void *)rpqp->rpq_queue)[rpqp->rpq_index],
 734                     0xFFFFFFFFFFFFFFFF);
 735                 (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
 736                     DDI_DMA_SYNC_FORDEV);
 737 
 738                 /*
 739                  * Update the reply index and keep looking for the
 740                  * reply if not found yet.
 741                  */
 742                 if (++rpqp->rpq_index == mpt->m_post_queue_depth) {
 743                         rpqp->rpq_index = 0;
 744                 }
 745 
 746                 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
 747                     rpqp->rpq_index);
 748                 if (!found_reply) {
 749                         continue;
 750                 }
 751 
 752                 break;
 753         }
 754 
 755         /*
 756          * clear the used slot as the last step.
 757          */
 758         slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
 759 }
 760 
 761 int
 762 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
 763 {
 764         int             config, i = 0, vol = (-1);
 765 
 766         for (config = 0; (config < mpt->m_num_raid_configs) && (vol != i);
 767             config++) {
 768                 for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
 769                         if (mpt->m_raidconfig[config].m_raidvol[i].
 770                             m_raidhandle == volid) {
 771                                 vol = i;
 772                                 break;
 773                         }
 774                 }
 775         }
 776 
 777         if (vol < 0) {
 778                 mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
 779                     "target.");
 780                 return (-1);
 781         }
 782 
 783         mpt->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
 784         mpt->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
 785         for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
 786                 mpt->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
 787                 mpt->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
 788         }
 789 
 790         return (0);
 791 }