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