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