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