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