The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mpt/mpt_raid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Routines for handling the integrated RAID features LSI MPT Fusion adapters.
    3  *
    4  * Copyright (c) 2005, WHEEL Sp. z o.o.
    5  * Copyright (c) 2005 Justin T. Gibbs.
    6  * All rights reserved.
    7  * 
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions are
   10  * met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   14  *    substantially similar to the "NO WARRANTY" disclaimer below
   15  *    ("Disclaimer") and any redistribution must be conditioned upon including
   16  *    a substantially similar Disclaimer requirement for further binary
   17  *    redistribution.
   18  * 3. Neither the names of the above listed copyright holders nor the names
   19  *    of any contributors may be used to endorse or promote products derived
   20  *    from this software without specific prior written permission.
   21  * 
   22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT
   32  * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 /*-
   35  * Some Breakage and Bug Fixing added later.
   36  * Copyright (c) 2006, by Matthew Jacob
   37  * All Rights Reserved
   38  *
   39  * Support from LSI-Logic has also gone a great deal toward making this a
   40  * workable subsystem and is gratefully acknowledged.
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __FBSDID("$FreeBSD$");
   45 
   46 #include <dev/mpt/mpt.h>
   47 #include <dev/mpt/mpt_raid.h>
   48 
   49 #include "dev/mpt/mpilib/mpi_ioc.h" /* XXX Fix Event Handling!!! */
   50 #include "dev/mpt/mpilib/mpi_raid.h"
   51 
   52 #include <cam/cam.h>
   53 #include <cam/cam_ccb.h>
   54 #include <cam/cam_sim.h>
   55 #include <cam/cam_xpt_sim.h>
   56 
   57 #if __FreeBSD_version < 500000
   58 #include <sys/devicestat.h>
   59 #define GIANT_REQUIRED
   60 #endif
   61 #include <cam/cam_periph.h>
   62 
   63 #include <sys/callout.h>
   64 #include <sys/kthread.h>
   65 #include <sys/sysctl.h>
   66 
   67 #include <machine/stdarg.h>
   68 
   69 struct mpt_raid_action_result
   70 {
   71         union {
   72                 MPI_RAID_VOL_INDICATOR  indicator_struct;
   73                 uint32_t                new_settings;
   74                 uint8_t                 phys_disk_num;
   75         } action_data;
   76         uint16_t                        action_status;
   77 };
   78 
   79 #define REQ_TO_RAID_ACTION_RESULT(req) ((struct mpt_raid_action_result *) \
   80         (((MSG_RAID_ACTION_REQUEST *)(req->req_vbuf)) + 1))
   81 
   82 #define REQ_IOCSTATUS(req) ((req)->IOCStatus & MPI_IOCSTATUS_MASK)
   83 
   84 
   85 static mpt_probe_handler_t      mpt_raid_probe;
   86 static mpt_attach_handler_t     mpt_raid_attach;
   87 static mpt_enable_handler_t     mpt_raid_enable;
   88 static mpt_event_handler_t      mpt_raid_event;
   89 static mpt_shutdown_handler_t   mpt_raid_shutdown;
   90 static mpt_reset_handler_t      mpt_raid_ioc_reset;
   91 static mpt_detach_handler_t     mpt_raid_detach;
   92 
   93 static struct mpt_personality mpt_raid_personality =
   94 {
   95         .name           = "mpt_raid",
   96         .probe          = mpt_raid_probe,
   97         .attach         = mpt_raid_attach,
   98         .enable         = mpt_raid_enable,
   99         .event          = mpt_raid_event,
  100         .reset          = mpt_raid_ioc_reset,
  101         .shutdown       = mpt_raid_shutdown,
  102         .detach         = mpt_raid_detach,
  103 };
  104 
  105 DECLARE_MPT_PERSONALITY(mpt_raid, SI_ORDER_THIRD);
  106 MPT_PERSONALITY_DEPEND(mpt_raid, mpt_cam, 1, 1, 1);
  107 
  108 static mpt_reply_handler_t mpt_raid_reply_handler;
  109 static int mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req,
  110                                         MSG_DEFAULT_REPLY *reply_frame);
  111 static int mpt_spawn_raid_thread(struct mpt_softc *mpt);
  112 static void mpt_terminate_raid_thread(struct mpt_softc *mpt);
  113 static void mpt_raid_thread(void *arg);
  114 static timeout_t mpt_raid_timer;
  115 #if 0
  116 static void mpt_enable_vol(struct mpt_softc *mpt,
  117                            struct mpt_raid_volume *mpt_vol, int enable);
  118 #endif
  119 static void mpt_verify_mwce(struct mpt_softc *mpt,
  120                             struct mpt_raid_volume *mpt_vol);
  121 static void mpt_adjust_queue_depth(struct mpt_softc *mpt,
  122                                    struct mpt_raid_volume *mpt_vol,
  123                                    struct cam_path *path);
  124 static void mpt_raid_sysctl_attach(struct mpt_softc *mpt);
  125 
  126 static uint32_t raid_handler_id = MPT_HANDLER_ID_NONE;
  127 
  128 const char *
  129 mpt_vol_type(struct mpt_raid_volume *vol)
  130 {
  131         switch (vol->config_page->VolumeType) {
  132         case MPI_RAID_VOL_TYPE_IS:
  133                 return ("RAID-0");
  134         case MPI_RAID_VOL_TYPE_IME:
  135                 return ("RAID-1E");
  136         case MPI_RAID_VOL_TYPE_IM:
  137                 return ("RAID-1");
  138         default:
  139                 return ("Unknown");
  140         }
  141 }
  142 
  143 const char *
  144 mpt_vol_state(struct mpt_raid_volume *vol)
  145 {
  146         switch (vol->config_page->VolumeStatus.State) {
  147         case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
  148                 return ("Optimal");
  149         case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
  150                 return ("Degraded");
  151         case MPI_RAIDVOL0_STATUS_STATE_FAILED:
  152                 return ("Failed");
  153         default:
  154                 return ("Unknown");
  155         }
  156 }
  157 
  158 const char *
  159 mpt_disk_state(struct mpt_raid_disk *disk)
  160 {
  161         switch (disk->config_page.PhysDiskStatus.State) {
  162         case MPI_PHYSDISK0_STATUS_ONLINE:
  163                 return ("Online");
  164         case MPI_PHYSDISK0_STATUS_MISSING:
  165                 return ("Missing");
  166         case MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE:
  167                 return ("Incompatible");
  168         case MPI_PHYSDISK0_STATUS_FAILED:
  169                 return ("Failed");
  170         case MPI_PHYSDISK0_STATUS_INITIALIZING:
  171                 return ("Initializing");
  172         case MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED:
  173                 return ("Offline Requested");
  174         case MPI_PHYSDISK0_STATUS_FAILED_REQUESTED:
  175                 return ("Failed per Host Request");
  176         case MPI_PHYSDISK0_STATUS_OTHER_OFFLINE:
  177                 return ("Offline");
  178         default:
  179                 return ("Unknown");
  180         }
  181 }
  182 
  183 void
  184 mpt_vol_prt(struct mpt_softc *mpt, struct mpt_raid_volume *vol,
  185             const char *fmt, ...)
  186 {
  187         va_list ap;
  188 
  189         printf("%s:vol%d(%s:%d:%d): ", device_get_nameunit(mpt->dev),
  190                (u_int)(vol - mpt->raid_volumes), device_get_nameunit(mpt->dev),
  191                vol->config_page->VolumeBus, vol->config_page->VolumeID);
  192         va_start(ap, fmt);
  193         vprintf(fmt, ap);
  194         va_end(ap);
  195 }
  196 
  197 void
  198 mpt_disk_prt(struct mpt_softc *mpt, struct mpt_raid_disk *disk,
  199              const char *fmt, ...)
  200 {
  201         va_list ap;
  202 
  203         if (disk->volume != NULL) {
  204                 printf("(%s:vol%d:%d): ",
  205                        device_get_nameunit(mpt->dev),
  206                        disk->volume->config_page->VolumeID,
  207                        disk->member_number);
  208         } else {
  209                 printf("(%s:%d:%d): ", device_get_nameunit(mpt->dev),
  210                        disk->config_page.PhysDiskBus,
  211                        disk->config_page.PhysDiskID);
  212         }
  213         va_start(ap, fmt);
  214         vprintf(fmt, ap);
  215         va_end(ap);
  216 }
  217 
  218 static void
  219 mpt_raid_async(void *callback_arg, u_int32_t code,
  220                struct cam_path *path, void *arg)
  221 {
  222         struct mpt_softc *mpt;
  223 
  224         mpt = (struct mpt_softc*)callback_arg;
  225         switch (code) {
  226         case AC_FOUND_DEVICE:
  227         {
  228                 struct ccb_getdev *cgd;
  229                 struct mpt_raid_volume *mpt_vol;
  230 
  231                 cgd = (struct ccb_getdev *)arg;
  232                 if (cgd == NULL) {
  233                         break;
  234                 }
  235 
  236                 mpt_lprt(mpt, MPT_PRT_DEBUG, "Callback for %d\n",
  237                          cgd->ccb_h.target_id);
  238                 
  239                 RAID_VOL_FOREACH(mpt, mpt_vol) {
  240                         if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
  241                                 continue;
  242 
  243                         if (mpt_vol->config_page->VolumeID 
  244                          == cgd->ccb_h.target_id) {
  245                                 mpt_adjust_queue_depth(mpt, mpt_vol, path);
  246                                 break;
  247                         }
  248                 }
  249         }
  250         default:
  251                 break;
  252         }
  253 }
  254 
  255 int
  256 mpt_raid_probe(struct mpt_softc *mpt)
  257 {
  258         if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) {
  259                 return (ENODEV);
  260         }
  261         return (0);
  262 }
  263 
  264 int
  265 mpt_raid_attach(struct mpt_softc *mpt)
  266 {
  267         struct ccb_setasync csa;
  268         mpt_handler_t    handler;
  269         int              error;
  270 
  271         mpt_callout_init(&mpt->raid_timer);
  272 
  273         handler.reply_handler = mpt_raid_reply_handler;
  274         error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
  275                                      &raid_handler_id);
  276         if (error != 0) {
  277                 mpt_prt(mpt, "Unable to register RAID haandler!\n");
  278                 goto cleanup;
  279         }
  280 
  281         error = mpt_spawn_raid_thread(mpt);
  282         if (error != 0) {
  283                 mpt_prt(mpt, "Unable to spawn RAID thread!\n");
  284                 goto cleanup;
  285         }
  286  
  287         xpt_setup_ccb(&csa.ccb_h, mpt->path, 5);
  288         csa.ccb_h.func_code = XPT_SASYNC_CB;
  289         csa.event_enable = AC_FOUND_DEVICE;
  290         csa.callback = mpt_raid_async;
  291         csa.callback_arg = mpt;
  292         MPTLOCK_2_CAMLOCK(mpt);
  293         xpt_action((union ccb *)&csa);
  294         CAMLOCK_2_MPTLOCK(mpt);
  295         if (csa.ccb_h.status != CAM_REQ_CMP) {
  296                 mpt_prt(mpt, "mpt_raid_attach: Unable to register "
  297                         "CAM async handler.\n");
  298         }
  299 
  300         mpt_raid_sysctl_attach(mpt);
  301         return (0);
  302 cleanup:
  303         mpt_raid_detach(mpt);
  304         return (error);
  305 }
  306 
  307 int
  308 mpt_raid_enable(struct mpt_softc *mpt)
  309 {
  310         return (0);
  311 }
  312 
  313 void
  314 mpt_raid_detach(struct mpt_softc *mpt)
  315 {
  316         struct ccb_setasync csa;
  317         mpt_handler_t handler;
  318 
  319         callout_stop(&mpt->raid_timer);
  320         mpt_terminate_raid_thread(mpt); 
  321 
  322         handler.reply_handler = mpt_raid_reply_handler;
  323         mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
  324                                raid_handler_id);
  325         xpt_setup_ccb(&csa.ccb_h, mpt->path, /*priority*/5);
  326         csa.ccb_h.func_code = XPT_SASYNC_CB;
  327         csa.event_enable = 0;
  328         csa.callback = mpt_raid_async;
  329         csa.callback_arg = mpt;
  330         MPTLOCK_2_CAMLOCK(mpt);
  331         xpt_action((union ccb *)&csa);
  332         CAMLOCK_2_MPTLOCK(mpt);
  333 }
  334 
  335 static void
  336 mpt_raid_ioc_reset(struct mpt_softc *mpt, int type)
  337 {
  338         /* Nothing to do yet. */
  339 }
  340 
  341 static const char *raid_event_txt[] =
  342 {
  343         "Volume Created",
  344         "Volume Deleted",
  345         "Volume Settings Changed",
  346         "Volume Status Changed",
  347         "Volume Physical Disk Membership Changed",
  348         "Physical Disk Created",
  349         "Physical Disk Deleted",
  350         "Physical Disk Settings Changed",
  351         "Physical Disk Status Changed",
  352         "Domain Validation Required",
  353         "SMART Data Received",
  354         "Replace Action Started",
  355 };
  356 
  357 static int
  358 mpt_raid_event(struct mpt_softc *mpt, request_t *req,
  359                MSG_EVENT_NOTIFY_REPLY *msg)
  360 {
  361         EVENT_DATA_RAID *raid_event;
  362         struct mpt_raid_volume *mpt_vol;
  363         struct mpt_raid_disk *mpt_disk;
  364         CONFIG_PAGE_RAID_VOL_0 *vol_pg;
  365         int i;
  366         int print_event;
  367 
  368         if (msg->Event != MPI_EVENT_INTEGRATED_RAID) {
  369                 return (0);
  370         }
  371 
  372         raid_event = (EVENT_DATA_RAID *)&msg->Data;
  373 
  374         mpt_vol = NULL;
  375         vol_pg = NULL;
  376         if (mpt->raid_volumes != NULL && mpt->ioc_page2 != NULL) {
  377                 for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
  378                         mpt_vol = &mpt->raid_volumes[i];
  379                         vol_pg = mpt_vol->config_page;
  380 
  381                         if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
  382                                 continue;
  383 
  384                         if (vol_pg->VolumeID == raid_event->VolumeID
  385                          && vol_pg->VolumeBus == raid_event->VolumeBus)
  386                                 break;
  387                 }
  388                 if (i >= mpt->ioc_page2->MaxVolumes) {
  389                         mpt_vol = NULL;
  390                         vol_pg = NULL;
  391                 }
  392         }
  393 
  394         mpt_disk = NULL;
  395         if (raid_event->PhysDiskNum != 0xFF && mpt->raid_disks != NULL) {
  396                 mpt_disk = mpt->raid_disks + raid_event->PhysDiskNum;
  397                 if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0) {
  398                         mpt_disk = NULL;
  399                 }
  400         }
  401 
  402         print_event = 1;
  403         switch(raid_event->ReasonCode) {
  404         case MPI_EVENT_RAID_RC_VOLUME_CREATED:
  405         case MPI_EVENT_RAID_RC_VOLUME_DELETED:
  406                 break;
  407         case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
  408                 if (mpt_vol != NULL) {
  409                         if ((mpt_vol->flags & MPT_RVF_UP2DATE) != 0) {
  410                                 mpt_vol->flags &= ~MPT_RVF_UP2DATE;
  411                         } else {
  412                                 /*
  413                                  * Coalesce status messages into one
  414                                  * per background run of our RAID thread.
  415                                  * This removes "spurious" status messages
  416                                  * from our output.
  417                                  */
  418                                 print_event = 0;
  419                         }
  420                 }
  421                 break;
  422         case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
  423         case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
  424                 mpt->raid_rescan++;
  425                 if (mpt_vol != NULL) {
  426                         mpt_vol->flags &= ~(MPT_RVF_UP2DATE|MPT_RVF_ANNOUNCED);
  427                 }
  428                 break;
  429         case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
  430         case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
  431                 mpt->raid_rescan++;
  432                 break;
  433         case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
  434         case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
  435                 mpt->raid_rescan++;
  436                 if (mpt_disk != NULL) {
  437                         mpt_disk->flags &= ~MPT_RDF_UP2DATE;
  438                 }
  439                 break;
  440         case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
  441                 mpt->raid_rescan++;
  442                 break;
  443         case MPI_EVENT_RAID_RC_SMART_DATA:
  444         case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
  445                 break;
  446         }
  447 
  448         if (print_event) {
  449                 if (mpt_disk != NULL) {
  450                         mpt_disk_prt(mpt, mpt_disk, "");
  451                 } else if (mpt_vol != NULL) {
  452                         mpt_vol_prt(mpt, mpt_vol, "");
  453                 } else {
  454                         mpt_prt(mpt, "Volume(%d:%d", raid_event->VolumeBus,
  455                                 raid_event->VolumeID);
  456 
  457                         if (raid_event->PhysDiskNum != 0xFF)
  458                                 mpt_prtc(mpt, ":%d): ",
  459                                          raid_event->PhysDiskNum);
  460                         else
  461                                 mpt_prtc(mpt, "): ");
  462                 }
  463 
  464                 if (raid_event->ReasonCode >= NUM_ELEMENTS(raid_event_txt))
  465                         mpt_prtc(mpt, "Unhandled RaidEvent %#x\n",
  466                                  raid_event->ReasonCode);
  467                 else
  468                         mpt_prtc(mpt, "%s\n",
  469                                  raid_event_txt[raid_event->ReasonCode]);
  470         }
  471 
  472         if (raid_event->ReasonCode == MPI_EVENT_RAID_RC_SMART_DATA) {
  473                 /* XXX Use CAM's print sense for this... */
  474                 if (mpt_disk != NULL)
  475                         mpt_disk_prt(mpt, mpt_disk, "");
  476                 else
  477                         mpt_prt(mpt, "Volume(%d:%d:%d: ",
  478                             raid_event->VolumeBus, raid_event->VolumeID,
  479                             raid_event->PhysDiskNum);
  480                 mpt_prtc(mpt, "ASC 0x%x, ASCQ 0x%x)\n",
  481                          raid_event->ASC, raid_event->ASCQ);
  482         }
  483 
  484         mpt_raid_wakeup(mpt);
  485         return (1);
  486 }
  487 
  488 static void
  489 mpt_raid_shutdown(struct mpt_softc *mpt)
  490 {
  491         struct mpt_raid_volume *mpt_vol;
  492 
  493         if (mpt->raid_mwce_setting != MPT_RAID_MWCE_REBUILD_ONLY) {
  494                 return;
  495         }
  496 
  497         mpt->raid_mwce_setting = MPT_RAID_MWCE_OFF;
  498         RAID_VOL_FOREACH(mpt, mpt_vol) {
  499                 mpt_verify_mwce(mpt, mpt_vol);
  500         }
  501 }
  502 
  503 static int
  504 mpt_raid_reply_handler(struct mpt_softc *mpt, request_t *req,
  505     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
  506 {
  507         int free_req;
  508 
  509         if (req == NULL)
  510                 return (TRUE);
  511 
  512         free_req = TRUE;
  513         if (reply_frame != NULL)
  514                 free_req = mpt_raid_reply_frame_handler(mpt, req, reply_frame);
  515 #ifdef NOTYET
  516         else if (req->ccb != NULL) {
  517                 /* Complete Quiesce CCB with error... */
  518         }
  519 #endif
  520 
  521         req->state &= ~REQ_STATE_QUEUED;
  522         req->state |= REQ_STATE_DONE;
  523         TAILQ_REMOVE(&mpt->request_pending_list, req, links);
  524 
  525         if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
  526                 wakeup(req);
  527         } else if (free_req) {
  528                 mpt_free_request(mpt, req);
  529         }
  530 
  531         return (TRUE);
  532 }
  533 
  534 /*
  535  * Parse additional completion information in the reply
  536  * frame for RAID I/O requests.
  537  */
  538 static int
  539 mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req,
  540     MSG_DEFAULT_REPLY *reply_frame)
  541 {
  542         MSG_RAID_ACTION_REPLY *reply;
  543         struct mpt_raid_action_result *action_result;
  544         MSG_RAID_ACTION_REQUEST *rap;
  545 
  546         reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
  547         req->IOCStatus = le16toh(reply->IOCStatus);
  548         rap = (MSG_RAID_ACTION_REQUEST *)req->req_vbuf;
  549         
  550         switch (rap->Action) {
  551         case MPI_RAID_ACTION_QUIESCE_PHYS_IO:
  552                 mpt_prt(mpt, "QUIESCE PHYSIO DONE\n");
  553                 break;
  554         case MPI_RAID_ACTION_ENABLE_PHYS_IO:
  555                 mpt_prt(mpt, "ENABLY PHYSIO DONE\n");
  556                 break;
  557         default:
  558                 break;
  559         }
  560         action_result = REQ_TO_RAID_ACTION_RESULT(req);
  561         memcpy(&action_result->action_data, &reply->ActionData,
  562             sizeof(action_result->action_data));
  563         action_result->action_status = reply->ActionStatus;
  564         return (TRUE);
  565 }
  566 
  567 /*
  568  * Utiltity routine to perform a RAID action command;
  569  */
  570 int
  571 mpt_issue_raid_req(struct mpt_softc *mpt, struct mpt_raid_volume *vol,
  572                    struct mpt_raid_disk *disk, request_t *req, u_int Action,
  573                    uint32_t ActionDataWord, bus_addr_t addr, bus_size_t len,
  574                    int write, int wait)
  575 {
  576         MSG_RAID_ACTION_REQUEST *rap;
  577         SGE_SIMPLE32 *se;
  578 
  579         rap = req->req_vbuf;
  580         memset(rap, 0, sizeof *rap);
  581         rap->Action = Action;
  582         rap->ActionDataWord = ActionDataWord;
  583         rap->Function = MPI_FUNCTION_RAID_ACTION;
  584         rap->VolumeID = vol->config_page->VolumeID;
  585         rap->VolumeBus = vol->config_page->VolumeBus;
  586         if (disk != 0)
  587                 rap->PhysDiskNum = disk->config_page.PhysDiskNum;
  588         else
  589                 rap->PhysDiskNum = 0xFF;
  590         se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
  591         se->Address = addr;
  592         MPI_pSGE_SET_LENGTH(se, len);
  593         MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
  594             MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
  595             MPI_SGE_FLAGS_END_OF_LIST |
  596             write ? MPI_SGE_FLAGS_HOST_TO_IOC : MPI_SGE_FLAGS_IOC_TO_HOST));
  597         rap->MsgContext = htole32(req->index | raid_handler_id);
  598 
  599         mpt_check_doorbell(mpt);
  600         mpt_send_cmd(mpt, req);
  601 
  602         if (wait) {
  603                 return (mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE,
  604                                      /*sleep_ok*/FALSE, /*time_ms*/2000));
  605         } else {
  606                 return (0);
  607         }
  608 }
  609 
  610 /*************************** RAID Status Monitoring ***************************/
  611 static int
  612 mpt_spawn_raid_thread(struct mpt_softc *mpt)
  613 {
  614         int error;
  615 
  616         /*
  617          * Freeze out any CAM transactions until our thread
  618          * is able to run at least once.  We need to update
  619          * our RAID pages before acception I/O or we may
  620          * reject I/O to an ID we later determine is for a
  621          * hidden physdisk.
  622          */
  623         xpt_freeze_simq(mpt->phydisk_sim, 1);
  624         error = mpt_kthread_create(mpt_raid_thread, mpt,
  625             &mpt->raid_thread, /*flags*/0, /*altstack*/0,
  626             "mpt_raid%d", mpt->unit);
  627         if (error != 0)
  628                 xpt_release_simq(mpt->phydisk_sim, /*run_queue*/FALSE);
  629         return (error);
  630 }
  631 
  632 static void
  633 mpt_terminate_raid_thread(struct mpt_softc *mpt)
  634 {
  635 
  636         if (mpt->raid_thread == NULL) {
  637                 return;
  638         }
  639         mpt->shutdwn_raid = 1;
  640         wakeup(mpt->raid_volumes);
  641         /*
  642          * Sleep on a slightly different location
  643          * for this interlock just for added safety.
  644          */
  645         mpt_sleep(mpt, &mpt->raid_thread, PUSER, "thtrm", 0);
  646 }
  647 
  648 static void
  649 mpt_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
  650 {
  651         xpt_free_path(ccb->ccb_h.path);
  652         free(ccb, M_DEVBUF);
  653 }
  654 
  655 static void
  656 mpt_raid_thread(void *arg)
  657 {
  658         struct mpt_softc *mpt;
  659         int firstrun;
  660 
  661 #if __FreeBSD_version >= 500000
  662         mtx_lock(&Giant);
  663 #endif
  664         mpt = (struct mpt_softc *)arg;
  665         firstrun = 1;
  666         MPT_LOCK(mpt);
  667         while (mpt->shutdwn_raid == 0) {
  668 
  669                 if (mpt->raid_wakeup == 0) {
  670                         mpt_sleep(mpt, &mpt->raid_volumes, PUSER, "idle", 0);
  671                         continue;
  672                 }
  673 
  674                 mpt->raid_wakeup = 0;
  675 
  676                 if (mpt_refresh_raid_data(mpt)) {
  677                         mpt_schedule_raid_refresh(mpt); /* XX NOT QUITE RIGHT */
  678                         continue;
  679                 }
  680 
  681                 /*
  682                  * Now that we have our first snapshot of RAID data,
  683                  * allow CAM to access our physical disk bus.
  684                  */
  685                 if (firstrun) {
  686                         firstrun = 0;
  687                         MPTLOCK_2_CAMLOCK(mpt);
  688                         xpt_release_simq(mpt->phydisk_sim, TRUE);
  689                         CAMLOCK_2_MPTLOCK(mpt);
  690                 }
  691 
  692                 if (mpt->raid_rescan != 0) {
  693                         union ccb *ccb;
  694                         struct cam_path *path;
  695                         int error;
  696 
  697                         mpt->raid_rescan = 0;
  698 
  699                         ccb = malloc(sizeof(*ccb), M_DEVBUF, M_WAITOK);
  700                         error = xpt_create_path(&path, xpt_periph,
  701                             cam_sim_path(mpt->phydisk_sim),
  702                             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
  703                         if (error != CAM_REQ_CMP) {
  704                                 free(ccb, M_DEVBUF);
  705                                 mpt_prt(mpt, "Unable to rescan RAID Bus!\n");
  706                         } else {
  707                                 xpt_setup_ccb(&ccb->ccb_h, path, 5);
  708                                 ccb->ccb_h.func_code = XPT_SCAN_BUS;
  709                                 ccb->ccb_h.cbfcnp = mpt_cam_rescan_callback;
  710                                 ccb->crcn.flags = CAM_FLAG_NONE;
  711                                 MPTLOCK_2_CAMLOCK(mpt);
  712                                 xpt_action(ccb);
  713                                 CAMLOCK_2_MPTLOCK(mpt);
  714                         }
  715                 }
  716         }
  717         mpt->raid_thread = NULL;
  718         wakeup(&mpt->raid_thread);
  719         MPT_UNLOCK(mpt);
  720 #if __FreeBSD_version >= 500000
  721         mtx_unlock(&Giant);
  722 #endif
  723         kthread_exit(0);
  724 }
  725 
  726 #if 0
  727 static void
  728 mpt_raid_quiesce_timeout(void *arg)
  729 {
  730         /* Complete the CCB with error */
  731         /* COWWWW */
  732 }
  733 
  734 static timeout_t mpt_raid_quiesce_timeout;
  735 cam_status
  736 mpt_raid_quiesce_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk,
  737                       request_t *req)
  738 {
  739         union ccb *ccb;
  740 
  741         ccb = req->ccb;
  742         if ((mpt_disk->flags & MPT_RDF_QUIESCED) != 0)
  743                 return (CAM_REQ_CMP);
  744 
  745         if ((mpt_disk->flags & MPT_RDF_QUIESCING) == 0) {
  746                 int rv;
  747 
  748                 mpt_disk->flags |= MPT_RDF_QUIESCING;
  749                 xpt_freeze_devq(ccb->ccb_h.path, 1);
  750                 
  751                 rv = mpt_issue_raid_req(mpt, mpt_disk->volume, mpt_disk, req,
  752                                         MPI_RAID_ACTION_QUIESCE_PHYS_IO,
  753                                         /*ActionData*/0, /*addr*/0,
  754                                         /*len*/0, /*write*/FALSE,
  755                                         /*wait*/FALSE);
  756                 if (rv != 0)
  757                         return (CAM_REQ_CMP_ERR);
  758 
  759                 ccb->ccb_h.timeout_ch =
  760                         timeout(mpt_raid_quiesce_timeout, (caddr_t)ccb, 5 * hz);
  761 #if 0
  762                 if (rv == ETIMEDOUT) {
  763                         mpt_disk_prt(mpt, mpt_disk, "mpt_raid_quiesce_disk: "
  764                                      "Quiece Timed-out\n");
  765                         xpt_release_devq(ccb->ccb_h.path, 1, /*run*/0);
  766                         return (CAM_REQ_CMP_ERR);
  767                 }
  768 
  769                 ar = REQ_TO_RAID_ACTION_RESULT(req);
  770                 if (rv != 0
  771                  || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
  772                  || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
  773                         mpt_disk_prt(mpt, mpt_disk, "Quiece Failed"
  774                                     "%d:%x:%x\n", rv, req->IOCStatus,
  775                                     ar->action_status);
  776                         xpt_release_devq(ccb->ccb_h.path, 1, /*run*/0);
  777                         return (CAM_REQ_CMP_ERR);
  778                 }
  779 #endif
  780                 return (CAM_REQ_INPROG);
  781         }
  782         return (CAM_REQUEUE_REQ);
  783 }
  784 #endif
  785 
  786 /* XXX Ignores that there may be multiple busses/IOCs involved. */
  787 cam_status
  788 mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, u_int *tgt)
  789 {
  790         struct mpt_raid_disk *mpt_disk;
  791 
  792         mpt_disk = mpt->raid_disks + ccb->ccb_h.target_id;
  793         if (ccb->ccb_h.target_id < mpt->raid_max_disks
  794          && (mpt_disk->flags & MPT_RDF_ACTIVE) != 0) {
  795                 *tgt = mpt_disk->config_page.PhysDiskID;
  796                 return (0);
  797         }
  798         mpt_lprt(mpt, MPT_PRT_DEBUG1, "mpt_map_physdisk(%d) - Not Active\n",
  799                  ccb->ccb_h.target_id);
  800         return (-1);
  801 }
  802 
  803 /* XXX Ignores that there may be multiple busses/IOCs involved. */
  804 int
  805 mpt_is_raid_volume(struct mpt_softc *mpt, int tgt)
  806 {
  807         CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol;
  808         CONFIG_PAGE_IOC_2_RAID_VOL *ioc_last_vol;
  809 
  810         if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) {
  811                 return (0);
  812         }
  813         ioc_vol = mpt->ioc_page2->RaidVolume;
  814         ioc_last_vol = ioc_vol + mpt->ioc_page2->NumActiveVolumes;
  815         for (;ioc_vol != ioc_last_vol; ioc_vol++) {
  816                 if (ioc_vol->VolumeID == tgt) {
  817                         return (1);
  818                 }
  819         }
  820         return (0);
  821 }
  822 
  823 #if 0
  824 static void
  825 mpt_enable_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
  826                int enable)
  827 {
  828         request_t *req;
  829         struct mpt_raid_action_result *ar;
  830         CONFIG_PAGE_RAID_VOL_0 *vol_pg;
  831         int enabled;
  832         int rv;
  833 
  834         vol_pg = mpt_vol->config_page;
  835         enabled = vol_pg->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED;
  836 
  837         /*
  838          * If the setting matches the configuration,
  839          * there is nothing to do.
  840          */
  841         if ((enabled && enable)
  842          || (!enabled && !enable))
  843                 return;
  844 
  845         req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
  846         if (req == NULL) {
  847                 mpt_vol_prt(mpt, mpt_vol,
  848                             "mpt_enable_vol: Get request failed!\n");
  849                 return;
  850         }
  851 
  852         rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
  853                                 enable ? MPI_RAID_ACTION_ENABLE_VOLUME
  854                                        : MPI_RAID_ACTION_DISABLE_VOLUME,
  855                                 /*data*/0, /*addr*/0, /*len*/0,
  856                                 /*write*/FALSE, /*wait*/TRUE);
  857         if (rv == ETIMEDOUT) {
  858                 mpt_vol_prt(mpt, mpt_vol, "mpt_enable_vol: "
  859                             "%s Volume Timed-out\n",
  860                             enable ? "Enable" : "Disable");
  861                 return;
  862         }
  863         ar = REQ_TO_RAID_ACTION_RESULT(req);
  864         if (rv != 0
  865          || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
  866          || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
  867                 mpt_vol_prt(mpt, mpt_vol, "%s Volume Failed: %d:%x:%x\n",
  868                             enable ? "Enable" : "Disable",
  869                             rv, req->IOCStatus, ar->action_status);
  870         }
  871 
  872         mpt_free_request(mpt, req);
  873 }
  874 #endif
  875 
  876 static void
  877 mpt_verify_mwce(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
  878 {
  879         request_t *req;
  880         struct mpt_raid_action_result *ar;
  881         CONFIG_PAGE_RAID_VOL_0 *vol_pg;
  882         uint32_t data;
  883         int rv;
  884         int resyncing;
  885         int mwce;
  886 
  887         vol_pg = mpt_vol->config_page;
  888         resyncing = vol_pg->VolumeStatus.Flags
  889                   & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
  890         mwce = vol_pg->VolumeSettings.Settings
  891              & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
  892 
  893         /*
  894          * If the setting matches the configuration,
  895          * there is nothing to do.
  896          */
  897         switch (mpt->raid_mwce_setting) {
  898         case MPT_RAID_MWCE_REBUILD_ONLY:
  899                 if ((resyncing && mwce) || (!resyncing && !mwce)) {
  900                         return;
  901                 }
  902                 mpt_vol->flags ^= MPT_RVF_WCE_CHANGED;
  903                 if ((mpt_vol->flags & MPT_RVF_WCE_CHANGED) == 0) {
  904                         /*
  905                          * Wait one more status update to see if
  906                          * resyncing gets enabled.  It gets disabled
  907                          * temporarilly when WCE is changed.
  908                          */
  909                         return;
  910                 }
  911                 break;
  912         case MPT_RAID_MWCE_ON:
  913                 if (mwce)
  914                         return;
  915                 break;
  916         case MPT_RAID_MWCE_OFF:
  917                 if (!mwce)
  918                         return;
  919                 break;
  920         case MPT_RAID_MWCE_NC:
  921                 return;
  922         }
  923 
  924         req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
  925         if (req == NULL) {
  926                 mpt_vol_prt(mpt, mpt_vol,
  927                             "mpt_verify_mwce: Get request failed!\n");
  928                 return;
  929         }
  930 
  931         vol_pg->VolumeSettings.Settings ^=
  932             MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
  933         memcpy(&data, &vol_pg->VolumeSettings, sizeof(data));
  934         vol_pg->VolumeSettings.Settings ^=
  935             MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
  936         rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
  937                                 MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
  938                                 data, /*addr*/0, /*len*/0,
  939                                 /*write*/FALSE, /*wait*/TRUE);
  940         if (rv == ETIMEDOUT) {
  941                 mpt_vol_prt(mpt, mpt_vol, "mpt_verify_mwce: "
  942                             "Write Cache Enable Timed-out\n");
  943                 return;
  944         }
  945         ar = REQ_TO_RAID_ACTION_RESULT(req);
  946         if (rv != 0
  947          || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
  948          || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
  949                 mpt_vol_prt(mpt, mpt_vol, "Write Cache Enable Failed: "
  950                             "%d:%x:%x\n", rv, req->IOCStatus,
  951                             ar->action_status);
  952         } else {
  953                 vol_pg->VolumeSettings.Settings ^=
  954                     MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
  955         }
  956         mpt_free_request(mpt, req);
  957 }
  958 
  959 static void
  960 mpt_verify_resync_rate(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
  961 {
  962         request_t *req;
  963         struct mpt_raid_action_result *ar;
  964         CONFIG_PAGE_RAID_VOL_0  *vol_pg;
  965         u_int prio;
  966         int rv;
  967 
  968         vol_pg = mpt_vol->config_page;
  969 
  970         if (mpt->raid_resync_rate == MPT_RAID_RESYNC_RATE_NC)
  971                 return;
  972 
  973         /*
  974          * If the current RAID resync rate does not
  975          * match our configured rate, update it.
  976          */
  977         prio = vol_pg->VolumeSettings.Settings
  978              & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
  979         if (vol_pg->ResyncRate != 0
  980          && vol_pg->ResyncRate != mpt->raid_resync_rate) {
  981 
  982                 req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
  983                 if (req == NULL) {
  984                         mpt_vol_prt(mpt, mpt_vol, "mpt_verify_resync_rate: "
  985                                     "Get request failed!\n");
  986                         return;
  987                 }
  988 
  989                 rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
  990                                         MPI_RAID_ACTION_SET_RESYNC_RATE,
  991                                         mpt->raid_resync_rate, /*addr*/0,
  992                                         /*len*/0, /*write*/FALSE, /*wait*/TRUE);
  993                 if (rv == ETIMEDOUT) {
  994                         mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_data: "
  995                                     "Resync Rate Setting Timed-out\n");
  996                         return;
  997                 }
  998 
  999                 ar = REQ_TO_RAID_ACTION_RESULT(req);
 1000                 if (rv != 0
 1001                  || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
 1002                  || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
 1003                         mpt_vol_prt(mpt, mpt_vol, "Resync Rate Setting Failed: "
 1004                                     "%d:%x:%x\n", rv, req->IOCStatus,
 1005                                     ar->action_status);
 1006                 } else 
 1007                         vol_pg->ResyncRate = mpt->raid_resync_rate;
 1008                 mpt_free_request(mpt, req);
 1009         } else if ((prio && mpt->raid_resync_rate < 128)
 1010                 || (!prio && mpt->raid_resync_rate >= 128)) {
 1011                 uint32_t data;
 1012 
 1013                 req = mpt_get_request(mpt, /*sleep_ok*/TRUE);
 1014                 if (req == NULL) {
 1015                         mpt_vol_prt(mpt, mpt_vol, "mpt_verify_resync_rate: "
 1016                                     "Get request failed!\n");
 1017                         return;
 1018                 }
 1019 
 1020                 vol_pg->VolumeSettings.Settings ^=
 1021                     MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
 1022                 memcpy(&data, &vol_pg->VolumeSettings, sizeof(data));
 1023                 vol_pg->VolumeSettings.Settings ^=
 1024                     MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
 1025                 rv = mpt_issue_raid_req(mpt, mpt_vol, /*disk*/NULL, req,
 1026                                         MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS,
 1027                                         data, /*addr*/0, /*len*/0,
 1028                                         /*write*/FALSE, /*wait*/TRUE);
 1029                 if (rv == ETIMEDOUT) {
 1030                         mpt_vol_prt(mpt, mpt_vol, "mpt_refresh_raid_data: "
 1031                                     "Resync Rate Setting Timed-out\n");
 1032                         return;
 1033                 }
 1034                 ar = REQ_TO_RAID_ACTION_RESULT(req);
 1035                 if (rv != 0
 1036                  || REQ_IOCSTATUS(req) != MPI_IOCSTATUS_SUCCESS
 1037                  || (ar->action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS)) {
 1038                         mpt_vol_prt(mpt, mpt_vol, "Resync Rate Setting Failed: "
 1039                                     "%d:%x:%x\n", rv, req->IOCStatus,
 1040                                     ar->action_status);
 1041                 } else {
 1042                         vol_pg->VolumeSettings.Settings ^=
 1043                             MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
 1044                 }
 1045 
 1046                 mpt_free_request(mpt, req);
 1047         }
 1048 }
 1049 
 1050 static void
 1051 mpt_adjust_queue_depth(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
 1052                        struct cam_path *path)
 1053 {
 1054         struct ccb_relsim crs;
 1055 
 1056         xpt_setup_ccb(&crs.ccb_h, path, /*priority*/5);
 1057         crs.ccb_h.func_code = XPT_REL_SIMQ;
 1058         crs.release_flags = RELSIM_ADJUST_OPENINGS;
 1059         crs.openings = mpt->raid_queue_depth;
 1060         xpt_action((union ccb *)&crs);
 1061         if (crs.ccb_h.status != CAM_REQ_CMP)
 1062                 mpt_vol_prt(mpt, mpt_vol, "mpt_adjust_queue_depth failed "
 1063                             "with CAM status %#x\n", crs.ccb_h.status);
 1064 }
 1065 
 1066 static void
 1067 mpt_announce_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol)
 1068 {
 1069         CONFIG_PAGE_RAID_VOL_0 *vol_pg;
 1070         u_int i;
 1071 
 1072         vol_pg = mpt_vol->config_page;
 1073         mpt_vol_prt(mpt, mpt_vol, "Settings (");
 1074         for (i = 1; i <= 0x8000; i <<= 1) {
 1075                 switch (vol_pg->VolumeSettings.Settings & i) {
 1076                 case MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE:
 1077                         mpt_prtc(mpt, " Member-WCE");
 1078                         break;
 1079                 case MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART:
 1080                         mpt_prtc(mpt, " Offline-On-SMART-Err");
 1081                         break;
 1082                 case MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE:
 1083                         mpt_prtc(mpt, " Hot-Plug-Spares");
 1084                         break;
 1085                 case MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC:
 1086                         mpt_prtc(mpt, " High-Priority-ReSync");
 1087                         break;
 1088                 default:
 1089                         break;
 1090                 }
 1091         }
 1092         mpt_prtc(mpt, " )\n");
 1093         if (vol_pg->VolumeSettings.HotSparePool != 0) {
 1094                 mpt_vol_prt(mpt, mpt_vol, "Using Spare Pool%s",
 1095                             powerof2(vol_pg->VolumeSettings.HotSparePool)
 1096                           ? ":" : "s:");
 1097                 for (i = 0; i < 8; i++) {
 1098                         u_int mask;
 1099 
 1100                         mask = 0x1 << i;
 1101                         if ((vol_pg->VolumeSettings.HotSparePool & mask) == 0)
 1102                                 continue;
 1103                         mpt_prtc(mpt, " %d", i);
 1104                 }
 1105                 mpt_prtc(mpt, "\n");
 1106         }
 1107         mpt_vol_prt(mpt, mpt_vol, "%d Members:\n", vol_pg->NumPhysDisks);
 1108         for (i = 0; i < vol_pg->NumPhysDisks; i++){
 1109                 struct mpt_raid_disk *mpt_disk;
 1110                 CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
 1111                 int pt_bus = cam_sim_bus(mpt->phydisk_sim);
 1112                 U8 f, s;
 1113 
 1114                 mpt_disk = mpt->raid_disks + vol_pg->PhysDisk[i].PhysDiskNum;
 1115                 disk_pg = &mpt_disk->config_page;
 1116                 mpt_prtc(mpt, "      ");
 1117                 mpt_prtc(mpt, "(%s:%d:%d:0): ", device_get_nameunit(mpt->dev),
 1118                          pt_bus, disk_pg->PhysDiskID);
 1119                 if (vol_pg->VolumeType == MPI_RAID_VOL_TYPE_IM) {
 1120                         mpt_prtc(mpt, "%s", mpt_disk->member_number == 0?
 1121                             "Primary" : "Secondary");
 1122                 } else {
 1123                         mpt_prtc(mpt, "Stripe Position %d",
 1124                                  mpt_disk->member_number);
 1125                 }
 1126                 f = disk_pg->PhysDiskStatus.Flags;
 1127                 s = disk_pg->PhysDiskStatus.State;
 1128                 if (f & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC) {
 1129                         mpt_prtc(mpt, " Out of Sync");
 1130                 }
 1131                 if (f & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED) {
 1132                         mpt_prtc(mpt, " Quiesced");
 1133                 }
 1134                 if (f & MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME) {
 1135                         mpt_prtc(mpt, " Inactive");
 1136                 }
 1137                 if (f & MPI_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS) {
 1138                         mpt_prtc(mpt, " Was Optimal");
 1139                 }
 1140                 if (f & MPI_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS) {
 1141                         mpt_prtc(mpt, " Was Non-Optimal");
 1142                 }
 1143                 switch (s) {
 1144                 case MPI_PHYSDISK0_STATUS_ONLINE:
 1145                         mpt_prtc(mpt, " Online");
 1146                         break;
 1147                 case MPI_PHYSDISK0_STATUS_MISSING:
 1148                         mpt_prtc(mpt, " Missing");
 1149                         break;
 1150                 case MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE:
 1151                         mpt_prtc(mpt, " Incompatible");
 1152                         break;
 1153                 case MPI_PHYSDISK0_STATUS_FAILED:
 1154                         mpt_prtc(mpt, " Failed");
 1155                         break;
 1156                 case MPI_PHYSDISK0_STATUS_INITIALIZING:
 1157                         mpt_prtc(mpt, " Initializing");
 1158                         break;
 1159                 case MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED:
 1160                         mpt_prtc(mpt, " Requested Offline");
 1161                         break;
 1162                 case MPI_PHYSDISK0_STATUS_FAILED_REQUESTED:
 1163                         mpt_prtc(mpt, " Requested Failed");
 1164                         break;
 1165                 case MPI_PHYSDISK0_STATUS_OTHER_OFFLINE:
 1166                 default:
 1167                         mpt_prtc(mpt, " Offline Other (%x)", s);
 1168                         break;
 1169                 }
 1170                 mpt_prtc(mpt, "\n");
 1171         }
 1172 }
 1173 
 1174 static void
 1175 mpt_announce_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk)
 1176 {
 1177         CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
 1178         int rd_bus = cam_sim_bus(mpt->sim);
 1179         int pt_bus = cam_sim_bus(mpt->phydisk_sim);
 1180         u_int i;
 1181 
 1182         disk_pg = &mpt_disk->config_page;
 1183         mpt_disk_prt(mpt, mpt_disk,
 1184                      "Physical (%s:%d:%d:0), Pass-thru (%s:%d:%d:0)\n",
 1185                      device_get_nameunit(mpt->dev), rd_bus,
 1186                      disk_pg->PhysDiskID, device_get_nameunit(mpt->dev),
 1187                      pt_bus, mpt_disk - mpt->raid_disks);
 1188         if (disk_pg->PhysDiskSettings.HotSparePool == 0)
 1189                 return;
 1190         mpt_disk_prt(mpt, mpt_disk, "Member of Hot Spare Pool%s",
 1191                      powerof2(disk_pg->PhysDiskSettings.HotSparePool)
 1192                    ? ":" : "s:");
 1193         for (i = 0; i < 8; i++) {
 1194                 u_int mask;
 1195 
 1196                 mask = 0x1 << i;
 1197                 if ((disk_pg->PhysDiskSettings.HotSparePool & mask) == 0)
 1198                         continue;
 1199                 mpt_prtc(mpt, " %d", i);
 1200         }
 1201         mpt_prtc(mpt, "\n");
 1202 }
 1203 
 1204 static void
 1205 mpt_refresh_raid_disk(struct mpt_softc *mpt, struct mpt_raid_disk *mpt_disk,
 1206                       IOC_3_PHYS_DISK *ioc_disk)
 1207 {
 1208         int rv;
 1209 
 1210         rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK,
 1211                                  /*PageNumber*/0, ioc_disk->PhysDiskNum,
 1212                                  &mpt_disk->config_page.Header,
 1213                                  /*sleep_ok*/TRUE, /*timeout_ms*/5000);
 1214         if (rv != 0) {
 1215                 mpt_prt(mpt, "mpt_refresh_raid_disk: "
 1216                         "Failed to read RAID Disk Hdr(%d)\n",
 1217                         ioc_disk->PhysDiskNum);
 1218                 return;
 1219         }
 1220         rv = mpt_read_cur_cfg_page(mpt, ioc_disk->PhysDiskNum,
 1221                                    &mpt_disk->config_page.Header,
 1222                                    sizeof(mpt_disk->config_page),
 1223                                    /*sleep_ok*/TRUE, /*timeout_ms*/5000);
 1224         if (rv != 0)
 1225                 mpt_prt(mpt, "mpt_refresh_raid_disk: "
 1226                         "Failed to read RAID Disk Page(%d)\n",
 1227                         ioc_disk->PhysDiskNum);
 1228 }
 1229 
 1230 static void
 1231 mpt_refresh_raid_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol,
 1232     CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol)
 1233 {
 1234         CONFIG_PAGE_RAID_VOL_0 *vol_pg;
 1235         struct mpt_raid_action_result *ar;
 1236         request_t *req;
 1237         int rv;
 1238         int i;
 1239 
 1240         vol_pg = mpt_vol->config_page;
 1241         mpt_vol->flags &= ~MPT_RVF_UP2DATE;
 1242 
 1243         rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0,
 1244             ioc_vol->VolumePageNumber, &vol_pg->Header, TRUE, 5000);
 1245         if (rv != 0) {
 1246                 mpt_vol_prt(mpt, mpt_vol,
 1247                     "mpt_refresh_raid_vol: Failed to read RAID Vol Hdr(%d)\n",
 1248                     ioc_vol->VolumePageNumber);
 1249                 return;
 1250         }
 1251 
 1252         rv = mpt_read_cur_cfg_page(mpt, ioc_vol->VolumePageNumber,
 1253             &vol_pg->Header, mpt->raid_page0_len, TRUE, 5000);
 1254         if (rv != 0) {
 1255                 mpt_vol_prt(mpt, mpt_vol,
 1256                     "mpt_refresh_raid_vol: Failed to read RAID Vol Page(%d)\n",
 1257                     ioc_vol->VolumePageNumber);
 1258                 return;
 1259         }
 1260         mpt2host_config_page_raid_vol_0(vol_pg);
 1261 
 1262         mpt_vol->flags |= MPT_RVF_ACTIVE;
 1263 
 1264         /* Update disk entry array data. */
 1265         for (i = 0; i < vol_pg->NumPhysDisks; i++) {
 1266                 struct mpt_raid_disk *mpt_disk;
 1267                 mpt_disk = mpt->raid_disks + vol_pg->PhysDisk[i].PhysDiskNum;
 1268                 mpt_disk->volume = mpt_vol;
 1269                 mpt_disk->member_number = vol_pg->PhysDisk[i].PhysDiskMap;
 1270                 if (vol_pg->VolumeType == MPI_RAID_VOL_TYPE_IM) {
 1271                         mpt_disk->member_number--;
 1272                 }
 1273         }
 1274 
 1275         if ((vol_pg->VolumeStatus.Flags
 1276            & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) == 0)
 1277                 return;
 1278 
 1279         req = mpt_get_request(mpt, TRUE);
 1280         if (req == NULL) {
 1281                 mpt_vol_prt(mpt, mpt_vol,
 1282                     "mpt_refresh_raid_vol: Get request failed!\n");
 1283                 return;
 1284         }
 1285         rv = mpt_issue_raid_req(mpt, mpt_vol, NULL, req,
 1286             MPI_RAID_ACTION_INDICATOR_STRUCT, 0, 0, 0, FALSE, TRUE);
 1287         if (rv == ETIMEDOUT) {
 1288                 mpt_vol_prt(mpt, mpt_vol,
 1289                     "mpt_refresh_raid_vol: Progress Indicator fetch timeout\n");
 1290                 mpt_free_request(mpt, req);
 1291                 return;
 1292         }
 1293 
 1294         ar = REQ_TO_RAID_ACTION_RESULT(req);
 1295         if (rv == 0
 1296          && ar->action_status == MPI_RAID_ACTION_ASTATUS_SUCCESS
 1297          && REQ_IOCSTATUS(req) == MPI_IOCSTATUS_SUCCESS) {
 1298                 memcpy(&mpt_vol->sync_progress,
 1299                        &ar->action_data.indicator_struct,
 1300                        sizeof(mpt_vol->sync_progress));
 1301                 mpt2host_mpi_raid_vol_indicator(&mpt_vol->sync_progress);
 1302         } else {
 1303                 mpt_vol_prt(mpt, mpt_vol,
 1304                     "mpt_refresh_raid_vol: Progress indicator fetch failed!\n");
 1305         }
 1306         mpt_free_request(mpt, req);
 1307 }
 1308 
 1309 /*
 1310  * Update in-core information about RAID support.  We update any entries
 1311  * that didn't previously exists or have been marked as needing to
 1312  * be updated by our event handler.  Interesting changes are displayed
 1313  * to the console.
 1314  */
 1315 int
 1316 mpt_refresh_raid_data(struct mpt_softc *mpt)
 1317 {
 1318         CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol;
 1319         CONFIG_PAGE_IOC_2_RAID_VOL *ioc_last_vol;
 1320         IOC_3_PHYS_DISK *ioc_disk;
 1321         IOC_3_PHYS_DISK *ioc_last_disk;
 1322         CONFIG_PAGE_RAID_VOL_0  *vol_pg;
 1323         size_t len;
 1324         int rv;
 1325         int i;
 1326         u_int nonopt_volumes;
 1327 
 1328         if (mpt->ioc_page2 == NULL || mpt->ioc_page3 == NULL) {
 1329                 return (0);
 1330         }
 1331 
 1332         /*
 1333          * Mark all items as unreferenced by the configuration.
 1334          * This allows us to find, report, and discard stale
 1335          * entries.
 1336          */
 1337         for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) {
 1338                 mpt->raid_disks[i].flags &= ~MPT_RDF_REFERENCED;
 1339         }
 1340         for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
 1341                 mpt->raid_volumes[i].flags &= ~MPT_RVF_REFERENCED;
 1342         }
 1343 
 1344         /*
 1345          * Get Physical Disk information.
 1346          */
 1347         len = mpt->ioc_page3->Header.PageLength * sizeof(uint32_t);
 1348         rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0,
 1349                                    &mpt->ioc_page3->Header, len,
 1350                                    /*sleep_ok*/TRUE, /*timeout_ms*/5000);
 1351         if (rv) {
 1352                 mpt_prt(mpt,
 1353                     "mpt_refresh_raid_data: Failed to read IOC Page 3\n");
 1354                 return (-1);
 1355         }
 1356 
 1357         ioc_disk = mpt->ioc_page3->PhysDisk;
 1358         ioc_last_disk = ioc_disk + mpt->ioc_page3->NumPhysDisks;
 1359         for (; ioc_disk != ioc_last_disk; ioc_disk++) {
 1360                 struct mpt_raid_disk *mpt_disk;
 1361 
 1362                 mpt_disk = mpt->raid_disks + ioc_disk->PhysDiskNum;
 1363                 mpt_disk->flags |= MPT_RDF_REFERENCED;
 1364                 if ((mpt_disk->flags & (MPT_RDF_ACTIVE|MPT_RDF_UP2DATE))
 1365                  != (MPT_RDF_ACTIVE|MPT_RDF_UP2DATE)) {
 1366 
 1367                         mpt_refresh_raid_disk(mpt, mpt_disk, ioc_disk);
 1368 
 1369                 }
 1370                 mpt_disk->flags |= MPT_RDF_ACTIVE;
 1371                 mpt->raid_rescan++;
 1372         }
 1373 
 1374         /*
 1375          * Refresh volume data.
 1376          */
 1377         len = mpt->ioc_page2->Header.PageLength * sizeof(uint32_t);
 1378         rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0,
 1379                                    &mpt->ioc_page2->Header, len,
 1380                                    /*sleep_ok*/TRUE, /*timeout_ms*/5000);
 1381         if (rv) {
 1382                 mpt_prt(mpt, "mpt_refresh_raid_data: "
 1383                         "Failed to read IOC Page 2\n");
 1384                 return (-1);
 1385         }
 1386 
 1387         ioc_vol = mpt->ioc_page2->RaidVolume;
 1388         ioc_last_vol = ioc_vol + mpt->ioc_page2->NumActiveVolumes;
 1389         for (;ioc_vol != ioc_last_vol; ioc_vol++) {
 1390                 struct mpt_raid_volume *mpt_vol;
 1391 
 1392                 mpt_vol = mpt->raid_volumes + ioc_vol->VolumePageNumber;
 1393                 mpt_vol->flags |= MPT_RVF_REFERENCED;
 1394                 vol_pg = mpt_vol->config_page;
 1395                 if (vol_pg == NULL)
 1396                         continue;
 1397                 if (((mpt_vol->flags & (MPT_RVF_ACTIVE|MPT_RVF_UP2DATE))
 1398                   != (MPT_RVF_ACTIVE|MPT_RVF_UP2DATE))
 1399                  || (vol_pg->VolumeStatus.Flags
 1400                    & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) != 0) {
 1401 
 1402                         mpt_refresh_raid_vol(mpt, mpt_vol, ioc_vol);
 1403                 }
 1404                 mpt_vol->flags |= MPT_RVF_ACTIVE;
 1405         }
 1406 
 1407         nonopt_volumes = 0;
 1408         for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) {
 1409                 struct mpt_raid_volume *mpt_vol;
 1410                 uint64_t total;
 1411                 uint64_t left;
 1412                 int m;
 1413                 u_int prio;
 1414 
 1415                 mpt_vol = &mpt->raid_volumes[i];
 1416 
 1417                 if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0) {
 1418                         continue;
 1419                 }
 1420 
 1421                 vol_pg = mpt_vol->config_page;
 1422                 if ((mpt_vol->flags & (MPT_RVF_REFERENCED|MPT_RVF_ANNOUNCED))
 1423                  == MPT_RVF_ANNOUNCED) {
 1424                         mpt_vol_prt(mpt, mpt_vol, "No longer configured\n");
 1425                         mpt_vol->flags = 0;
 1426                         continue;
 1427                 }
 1428 
 1429                 if ((mpt_vol->flags & MPT_RVF_ANNOUNCED) == 0) {
 1430                         mpt_announce_vol(mpt, mpt_vol);
 1431                         mpt_vol->flags |= MPT_RVF_ANNOUNCED;
 1432                 }
 1433 
 1434                 if (vol_pg->VolumeStatus.State !=
 1435                     MPI_RAIDVOL0_STATUS_STATE_OPTIMAL)
 1436                         nonopt_volumes++;
 1437 
 1438                 if ((mpt_vol->flags & MPT_RVF_UP2DATE) != 0)
 1439                         continue;
 1440 
 1441                 mpt_vol->flags |= MPT_RVF_UP2DATE;
 1442                 mpt_vol_prt(mpt, mpt_vol, "%s - %s\n",
 1443                     mpt_vol_type(mpt_vol), mpt_vol_state(mpt_vol));
 1444                 mpt_verify_mwce(mpt, mpt_vol);
 1445 
 1446                 if (vol_pg->VolumeStatus.Flags == 0) {
 1447                         continue;
 1448                 }
 1449 
 1450                 mpt_vol_prt(mpt, mpt_vol, "Status (");
 1451                 for (m = 1; m <= 0x80; m <<= 1) {
 1452                         switch (vol_pg->VolumeStatus.Flags & m) {
 1453                         case MPI_RAIDVOL0_STATUS_FLAG_ENABLED:
 1454                                 mpt_prtc(mpt, " Enabled");
 1455                                 break;
 1456                         case MPI_RAIDVOL0_STATUS_FLAG_QUIESCED:
 1457                                 mpt_prtc(mpt, " Quiesced");
 1458                                 break;
 1459                         case MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS:
 1460                                 mpt_prtc(mpt, " Re-Syncing");
 1461                                 break;
 1462                         case MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE:
 1463                                 mpt_prtc(mpt, " Inactive");
 1464                                 break;
 1465                         default:
 1466                                 break;
 1467                         }
 1468                 }
 1469                 mpt_prtc(mpt, " )\n");
 1470 
 1471                 if ((vol_pg->VolumeStatus.Flags
 1472                    & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) == 0)
 1473                         continue;
 1474 
 1475                 mpt_verify_resync_rate(mpt, mpt_vol);
 1476 
 1477                 left = MPT_U64_2_SCALAR(mpt_vol->sync_progress.BlocksRemaining);
 1478                 total = MPT_U64_2_SCALAR(mpt_vol->sync_progress.TotalBlocks);
 1479                 if (vol_pg->ResyncRate != 0) {
 1480 
 1481                         prio = ((u_int)vol_pg->ResyncRate * 100000) / 0xFF;
 1482                         mpt_vol_prt(mpt, mpt_vol, "Rate %d.%d%%\n",
 1483                             prio / 1000, prio % 1000);
 1484                 } else {
 1485                         prio = vol_pg->VolumeSettings.Settings
 1486                              & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
 1487                         mpt_vol_prt(mpt, mpt_vol, "%s Priority Re-Sync\n",
 1488                             prio ? "High" : "Low");
 1489                 }
 1490 #if __FreeBSD_version >= 500000
 1491                 mpt_vol_prt(mpt, mpt_vol, "%ju of %ju "
 1492                             "blocks remaining\n", (uintmax_t)left,
 1493                             (uintmax_t)total);
 1494 #else
 1495                 mpt_vol_prt(mpt, mpt_vol, "%llu of %llu "
 1496                             "blocks remaining\n", (uint64_t)left,
 1497                             (uint64_t)total);
 1498 #endif
 1499 
 1500                 /* Periodically report on sync progress. */
 1501                 mpt_schedule_raid_refresh(mpt);
 1502         }
 1503 
 1504         for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) {
 1505                 struct mpt_raid_disk *mpt_disk;
 1506                 CONFIG_PAGE_RAID_PHYS_DISK_0 *disk_pg;
 1507                 int m;
 1508 
 1509                 mpt_disk = &mpt->raid_disks[i];
 1510                 disk_pg = &mpt_disk->config_page;
 1511 
 1512                 if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0)
 1513                         continue;
 1514 
 1515                 if ((mpt_disk->flags & (MPT_RDF_REFERENCED|MPT_RDF_ANNOUNCED))
 1516                  == MPT_RDF_ANNOUNCED) {
 1517                         mpt_disk_prt(mpt, mpt_disk, "No longer configured\n");
 1518                         mpt_disk->flags = 0;
 1519                         mpt->raid_rescan++;
 1520                         continue;
 1521                 }
 1522 
 1523                 if ((mpt_disk->flags & MPT_RDF_ANNOUNCED) == 0) {
 1524 
 1525                         mpt_announce_disk(mpt, mpt_disk);
 1526                         mpt_disk->flags |= MPT_RVF_ANNOUNCED;
 1527                 }
 1528 
 1529                 if ((mpt_disk->flags & MPT_RDF_UP2DATE) != 0)
 1530                         continue;
 1531 
 1532                 mpt_disk->flags |= MPT_RDF_UP2DATE;
 1533                 mpt_disk_prt(mpt, mpt_disk, "%s\n", mpt_disk_state(mpt_disk));
 1534                 if (disk_pg->PhysDiskStatus.Flags == 0)
 1535                         continue;
 1536 
 1537                 mpt_disk_prt(mpt, mpt_disk, "Status (");
 1538                 for (m = 1; m <= 0x80; m <<= 1) {
 1539                         switch (disk_pg->PhysDiskStatus.Flags & m) {
 1540                         case MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC:
 1541                                 mpt_prtc(mpt, " Out-Of-Sync");
 1542                                 break;
 1543                         case MPI_PHYSDISK0_STATUS_FLAG_QUIESCED:
 1544                                 mpt_prtc(mpt, " Quiesced");
 1545                                 break;
 1546                         default:
 1547                                 break;
 1548                         }
 1549                 }
 1550                 mpt_prtc(mpt, " )\n");
 1551         }
 1552 
 1553         mpt->raid_nonopt_volumes = nonopt_volumes;
 1554         return (0);
 1555 }
 1556 
 1557 static void
 1558 mpt_raid_timer(void *arg)
 1559 {
 1560         struct mpt_softc *mpt;
 1561 
 1562         mpt = (struct mpt_softc *)arg;
 1563         MPT_LOCK(mpt);
 1564         mpt_raid_wakeup(mpt);
 1565         MPT_UNLOCK(mpt);
 1566 }
 1567 
 1568 void
 1569 mpt_schedule_raid_refresh(struct mpt_softc *mpt)
 1570 {
 1571         callout_reset(&mpt->raid_timer, MPT_RAID_SYNC_REPORT_INTERVAL,
 1572                       mpt_raid_timer, mpt);
 1573 }
 1574 
 1575 void
 1576 mpt_raid_free_mem(struct mpt_softc *mpt)
 1577 {
 1578 
 1579         if (mpt->raid_volumes) {
 1580                 struct mpt_raid_volume *mpt_raid;
 1581                 int i;
 1582                 for (i = 0; i < mpt->raid_max_volumes; i++) {
 1583                         mpt_raid = &mpt->raid_volumes[i];
 1584                         if (mpt_raid->config_page) {
 1585                                 free(mpt_raid->config_page, M_DEVBUF);
 1586                                 mpt_raid->config_page = NULL;
 1587                         }
 1588                 }
 1589                 free(mpt->raid_volumes, M_DEVBUF);
 1590                 mpt->raid_volumes = NULL;
 1591         }
 1592         if (mpt->raid_disks) {
 1593                 free(mpt->raid_disks, M_DEVBUF);
 1594                 mpt->raid_disks = NULL;
 1595         }
 1596         if (mpt->ioc_page2) {
 1597                 free(mpt->ioc_page2, M_DEVBUF);
 1598                 mpt->ioc_page2 = NULL;
 1599         }
 1600         if (mpt->ioc_page3) {
 1601                 free(mpt->ioc_page3, M_DEVBUF);
 1602                 mpt->ioc_page3 = NULL;
 1603         }
 1604         mpt->raid_max_volumes =  0;
 1605         mpt->raid_max_disks =  0;
 1606 }
 1607 
 1608 static int
 1609 mpt_raid_set_vol_resync_rate(struct mpt_softc *mpt, u_int rate)
 1610 {
 1611         struct mpt_raid_volume *mpt_vol;
 1612 
 1613         if ((rate > MPT_RAID_RESYNC_RATE_MAX
 1614           || rate < MPT_RAID_RESYNC_RATE_MIN)
 1615          && rate != MPT_RAID_RESYNC_RATE_NC)
 1616                 return (EINVAL);
 1617 
 1618         MPT_LOCK(mpt);
 1619         mpt->raid_resync_rate = rate;
 1620         RAID_VOL_FOREACH(mpt, mpt_vol) {
 1621                 if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0) {
 1622                         continue;
 1623                 }
 1624                 mpt_verify_resync_rate(mpt, mpt_vol);
 1625         }
 1626         MPT_UNLOCK(mpt);
 1627         return (0);
 1628 }
 1629 
 1630 static int
 1631 mpt_raid_set_vol_queue_depth(struct mpt_softc *mpt, u_int vol_queue_depth)
 1632 {
 1633         struct mpt_raid_volume *mpt_vol;
 1634 
 1635         if (vol_queue_depth > 255 || vol_queue_depth < 1)
 1636                 return (EINVAL);
 1637 
 1638         MPT_LOCK(mpt);
 1639         mpt->raid_queue_depth = vol_queue_depth;
 1640         RAID_VOL_FOREACH(mpt, mpt_vol) {
 1641                 struct cam_path *path;
 1642                 int error;
 1643 
 1644                 if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
 1645                         continue;
 1646 
 1647                 mpt->raid_rescan = 0;
 1648 
 1649                 MPTLOCK_2_CAMLOCK(mpt);
 1650                 error = xpt_create_path(&path, xpt_periph,
 1651                                         cam_sim_path(mpt->sim),
 1652                                         mpt_vol->config_page->VolumeID,
 1653                                         /*lun*/0);
 1654                 if (error != CAM_REQ_CMP) {
 1655                         CAMLOCK_2_MPTLOCK(mpt);
 1656                         mpt_vol_prt(mpt, mpt_vol, "Unable to allocate path!\n");
 1657                         continue;
 1658                 }
 1659                 mpt_adjust_queue_depth(mpt, mpt_vol, path);
 1660                 xpt_free_path(path);
 1661                 CAMLOCK_2_MPTLOCK(mpt);
 1662         }
 1663         MPT_UNLOCK(mpt);
 1664         return (0);
 1665 }
 1666 
 1667 static int
 1668 mpt_raid_set_vol_mwce(struct mpt_softc *mpt, mpt_raid_mwce_t mwce)
 1669 {
 1670         struct mpt_raid_volume *mpt_vol;
 1671         int force_full_resync;
 1672 
 1673         MPT_LOCK(mpt);
 1674         if (mwce == mpt->raid_mwce_setting) {
 1675                 MPT_UNLOCK(mpt);
 1676                 return (0);
 1677         }
 1678 
 1679         /*
 1680          * Catch MWCE being left on due to a failed shutdown.  Since
 1681          * sysctls cannot be set by the loader, we treat the first
 1682          * setting of this varible specially and force a full volume
 1683          * resync if MWCE is enabled and a resync is in progress.
 1684          */
 1685         force_full_resync = 0;
 1686         if (mpt->raid_mwce_set == 0
 1687          && mpt->raid_mwce_setting == MPT_RAID_MWCE_NC
 1688          && mwce == MPT_RAID_MWCE_REBUILD_ONLY)
 1689                 force_full_resync = 1;
 1690 
 1691         mpt->raid_mwce_setting = mwce;
 1692         RAID_VOL_FOREACH(mpt, mpt_vol) {
 1693                 CONFIG_PAGE_RAID_VOL_0 *vol_pg;
 1694                 int resyncing;
 1695                 int mwce;
 1696 
 1697                 if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0)
 1698                         continue;
 1699 
 1700                 vol_pg = mpt_vol->config_page;
 1701                 resyncing = vol_pg->VolumeStatus.Flags
 1702                           & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
 1703                 mwce = vol_pg->VolumeSettings.Settings
 1704                      & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
 1705                 if (force_full_resync && resyncing && mwce) {
 1706 
 1707                         /*
 1708                          * XXX disable/enable volume should force a resync,
 1709                          *     but we'll need to queice, drain, and restart
 1710                          *     I/O to do that.
 1711                          */
 1712                         mpt_vol_prt(mpt, mpt_vol, "WARNING - Unsafe shutdown "
 1713                                     "detected.  Suggest full resync.\n");
 1714                 }
 1715                 mpt_verify_mwce(mpt, mpt_vol);
 1716         }
 1717         mpt->raid_mwce_set = 1;
 1718         MPT_UNLOCK(mpt);
 1719         return (0);
 1720 }
 1721 
 1722 const char *mpt_vol_mwce_strs[] =
 1723 {
 1724         "On",
 1725         "Off",
 1726         "On-During-Rebuild",
 1727         "NC"
 1728 };
 1729 
 1730 static int
 1731 mpt_raid_sysctl_vol_member_wce(SYSCTL_HANDLER_ARGS)
 1732 {
 1733         char inbuf[20];
 1734         struct mpt_softc *mpt;
 1735         const char *str;
 1736         int error;
 1737         u_int size;
 1738         u_int i;
 1739 
 1740         GIANT_REQUIRED;
 1741 
 1742         mpt = (struct mpt_softc *)arg1;
 1743         str = mpt_vol_mwce_strs[mpt->raid_mwce_setting];
 1744         error = SYSCTL_OUT(req, str, strlen(str) + 1);
 1745         if (error || !req->newptr) {
 1746                 return (error);
 1747         }
 1748 
 1749         size = req->newlen - req->newidx;
 1750         if (size >= sizeof(inbuf)) {
 1751                 return (EINVAL);
 1752         }
 1753 
 1754         error = SYSCTL_IN(req, inbuf, size);
 1755         if (error) {
 1756                 return (error);
 1757         }
 1758         inbuf[size] = '\0'; 
 1759         for (i = 0; i < NUM_ELEMENTS(mpt_vol_mwce_strs); i++) {
 1760                 if (strcmp(mpt_vol_mwce_strs[i], inbuf) == 0) {
 1761                         return (mpt_raid_set_vol_mwce(mpt, i));
 1762                 }
 1763         }
 1764         return (EINVAL);
 1765 }
 1766 
 1767 static int
 1768 mpt_raid_sysctl_vol_resync_rate(SYSCTL_HANDLER_ARGS)
 1769 {
 1770         struct mpt_softc *mpt;
 1771         u_int raid_resync_rate;
 1772         int error;
 1773 
 1774         GIANT_REQUIRED;
 1775 
 1776         mpt = (struct mpt_softc *)arg1;
 1777         raid_resync_rate = mpt->raid_resync_rate;
 1778 
 1779         error = sysctl_handle_int(oidp, &raid_resync_rate, 0, req);
 1780         if (error || !req->newptr) {
 1781                 return error;
 1782         }
 1783 
 1784         return (mpt_raid_set_vol_resync_rate(mpt, raid_resync_rate));
 1785 }
 1786 
 1787 static int
 1788 mpt_raid_sysctl_vol_queue_depth(SYSCTL_HANDLER_ARGS)
 1789 {
 1790         struct mpt_softc *mpt;
 1791         u_int raid_queue_depth;
 1792         int error;
 1793 
 1794         GIANT_REQUIRED;
 1795 
 1796         mpt = (struct mpt_softc *)arg1;
 1797         raid_queue_depth = mpt->raid_queue_depth;
 1798 
 1799         error = sysctl_handle_int(oidp, &raid_queue_depth, 0, req);
 1800         if (error || !req->newptr) {
 1801                 return error;
 1802         }
 1803 
 1804         return (mpt_raid_set_vol_queue_depth(mpt, raid_queue_depth));
 1805 }
 1806 
 1807 static void
 1808 mpt_raid_sysctl_attach(struct mpt_softc *mpt)
 1809 {
 1810 #if __FreeBSD_version >= 500000
 1811         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(mpt->dev);
 1812         struct sysctl_oid *tree = device_get_sysctl_tree(mpt->dev);
 1813 
 1814         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 1815                         "vol_member_wce", CTLTYPE_STRING | CTLFLAG_RW, mpt, 0,
 1816                         mpt_raid_sysctl_vol_member_wce, "A",
 1817                         "volume member WCE(On,Off,On-During-Rebuild,NC)");
 1818 
 1819         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 1820                         "vol_queue_depth", CTLTYPE_INT | CTLFLAG_RW, mpt, 0,
 1821                         mpt_raid_sysctl_vol_queue_depth, "I",
 1822                         "default volume queue depth");
 1823 
 1824         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 1825                         "vol_resync_rate", CTLTYPE_INT | CTLFLAG_RW, mpt, 0,
 1826                         mpt_raid_sysctl_vol_resync_rate, "I",
 1827                         "volume resync priority (0 == NC, 1 - 255)");
 1828         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 1829                         "nonoptimal_volumes", CTLFLAG_RD,
 1830                         &mpt->raid_nonopt_volumes, 0,
 1831                         "number of nonoptimal volumes");
 1832 #endif
 1833 }

Cache object: 3f62a806d6a65cce7b5ef77646bb46a5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.