DEV messaging stage 1/4: Rearrange struct cdevsw and add a message port
[dragonfly.git] / sys / dev / disk / ata / ata-raid.c
1 /*-
2  * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/ata/ata-raid.c,v 1.3.2.19 2003/01/30 07:19:59 sos Exp $
29  * $DragonFly: src/sys/dev/disk/ata/ata-raid.c,v 1.6 2003/07/21 05:50:27 dillon Exp $
30  */
31
32 #include "opt_ata.h"
33 #include <sys/param.h>
34 #include <sys/systm.h> 
35 #include <sys/ata.h> 
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/buf.h>
39 #include <sys/bus.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/devicestat.h>
43 #include <sys/cons.h>
44 #include <machine/bus.h>
45 #include <sys/rman.h>
46 #include <dev/ata/ata-all.h>
47 #include <dev/ata/ata-disk.h>
48 #include <dev/ata/ata-raid.h>
49 #include <sys/proc.h>
50 #include <sys/buf2.h>
51
52 /* device structures */
53 static d_open_t         aropen;
54 static d_strategy_t     arstrategy;
55
56 static struct cdevsw ar_cdevsw = {
57         /* name */      "ar",
58         /* maj */       157,
59         /* flags */     D_DISK,
60         /* port */      NULL,
61         /* autoq */     0,
62
63         /* open */      aropen,
64         /* close */     nullclose,
65         /* read */      physread,
66         /* write */     physwrite,
67         /* ioctl */     noioctl, 
68         /* poll */      nopoll,
69         /* mmap */      nommap,
70         /* strategy */  arstrategy,
71         /* dump */      nodump,
72         /* psize */     nopsize
73 };  
74 static struct cdevsw ardisk_cdevsw;
75
76 /* prototypes */
77 static void ar_attach_raid(struct ar_softc *, int);
78 static void ar_done(struct buf *);
79 static void ar_config_changed(struct ar_softc *, int);
80 static int ar_rebuild(struct ar_softc *);
81 static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **);
82 static int ar_highpoint_write_conf(struct ar_softc *);
83 static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int);
84 static int ar_promise_write_conf(struct ar_softc *);
85 static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int);
86 static struct ata_device *ar_locate_disk(int);
87
88 /* internal vars */
89 static struct ar_softc **ar_table = NULL;
90 static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver");
91
92 int
93 ata_raiddisk_attach(struct ad_softc *adp)
94 {
95     struct ar_softc *rdp;
96     int array, disk;
97
98     if (ar_table) {
99         for (array = 0; array < MAX_ARRAYS; array++) {
100             if (!(rdp = ar_table[array]) || !rdp->flags)
101                 continue;
102    
103             for (disk = 0; disk < rdp->total_disks; disk++) {
104                 if ((rdp->disks[disk].flags & AR_DF_ASSIGNED) &&
105                     rdp->disks[disk].device == adp->device) {
106                     ata_prtdev(rdp->disks[disk].device,
107                                "inserted into ar%d disk%d as spare\n",
108                                array, disk);
109                     rdp->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE);
110                     AD_SOFTC(rdp->disks[disk])->flags = AD_F_RAID_SUBDISK;
111                     ar_config_changed(rdp, 1);
112                     return 1;
113                 }
114             }
115         }
116     }
117
118     if (!ar_table)
119         ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
120                           M_AR, M_NOWAIT | M_ZERO);
121     if (!ar_table) {
122         ata_prtdev(adp->device, "no memory for ATA raid array\n");
123         return 0;
124     }
125
126     switch(adp->device->channel->chiptype) {
127     case 0x4d33105a: case 0x4d38105a: case 0x4d30105a:
128     case 0x0d30105a: case 0x4d68105a: case 0x6268105a:
129     case 0x4d69105a: case 0x5275105a: case 0x6269105a:
130     case 0x7275105a:
131         /* test RAID bit in PCI reg XXX */
132         return (ar_promise_read_conf(adp, ar_table, 0));
133
134     case 0x00041103: case 0x00051103: case 0x00081103:
135         return (ar_highpoint_read_conf(adp, ar_table));
136
137     default:
138         return (ar_promise_read_conf(adp, ar_table, 1));
139     }
140     return 0;
141 }
142
143 int
144 ata_raiddisk_detach(struct ad_softc *adp)
145 {
146     struct ar_softc *rdp;
147     int array, disk;
148
149     if (ar_table) {
150         for (array = 0; array < MAX_ARRAYS; array++) {
151             if (!(rdp = ar_table[array]) || !rdp->flags)
152                 continue; 
153             for (disk = 0; disk < rdp->total_disks; disk++) {
154                 if (rdp->disks[disk].device == adp->device) {
155                     ata_prtdev(rdp->disks[disk].device,
156                                "deleted from ar%d disk%d\n", array, disk);
157                     rdp->disks[disk].flags &= ~(AR_DF_PRESENT | AR_DF_ONLINE);
158                     AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
159                     ar_config_changed(rdp, 1);
160                     return 1;
161                 }
162             }
163         }
164     }
165     return 0;
166 }
167
168 void
169 ata_raid_attach()
170 {
171     struct ar_softc *rdp;
172     int array;
173
174     if (!ar_table)
175         return;
176
177     for (array = 0; array < MAX_ARRAYS; array++) {
178         if (!(rdp = ar_table[array]) || !rdp->flags)
179             continue;
180         ar_attach_raid(rdp, 0);
181     }
182 }
183
184 static void
185 ar_attach_raid(struct ar_softc *rdp, int update)
186 {
187     dev_t dev;
188     int disk;
189
190     ar_config_changed(rdp, update);
191     dev = disk_create(rdp->lun, &rdp->disk, 0, &ar_cdevsw, &ardisk_cdevsw);
192     dev->si_drv1 = rdp;
193     dev->si_iosize_max = 256 * DEV_BSIZE;
194     rdp->dev = dev;
195
196     printf("ar%d: %lluMB <ATA ", rdp->lun, (unsigned long long)
197            (rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE)));
198     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
199     case AR_F_RAID0:
200         printf("RAID0 "); break;
201     case AR_F_RAID1:
202         printf("RAID1 "); break;
203     case AR_F_SPAN:
204         printf("SPAN "); break;
205     case (AR_F_RAID0 | AR_F_RAID1):
206         printf("RAID0+1 "); break;
207     default:
208         printf("unknown 0x%x> ", rdp->flags);
209         return;
210     }
211     printf("array> [%d/%d/%d] status: ",
212            rdp->cylinders, rdp->heads, rdp->sectors);
213     switch (rdp->flags & (AR_F_DEGRADED | AR_F_READY)) {
214     case AR_F_READY:
215         printf("READY");
216         break;
217     case (AR_F_DEGRADED | AR_F_READY):
218         printf("DEGRADED");
219         break;
220     default:
221         printf("BROKEN");
222         break;
223     }
224     printf(" subdisks:\n");
225     for (disk = 0; disk < rdp->total_disks; disk++) {
226         if (rdp->disks[disk].flags & AR_DF_PRESENT) {
227             if (rdp->disks[disk].flags & AR_DF_ONLINE)
228                 printf(" %d READY ", disk);
229             else if (rdp->disks[disk].flags & AR_DF_SPARE)
230                 printf(" %d SPARE ", disk);
231             else
232                 printf(" %d FREE  ", disk);
233             ad_print(AD_SOFTC(rdp->disks[disk]));
234             printf("         ");
235             ata_enclosure_print(AD_SOFTC(rdp->disks[disk])->device);
236         }
237         else if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
238             printf(" %d DOWN\n", disk);
239         else
240             printf(" %d INVALID no RAID config info on this disk\n", disk);
241     }
242 }
243
244 int
245 ata_raid_create(struct raid_setup *setup)
246 {
247     struct ata_device *atadev;
248     struct ar_softc *rdp;
249     int array, disk;
250     int ctlr = 0, disk_size = 0, total_disks = 0;
251
252     if (!ar_table)
253         ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
254                           M_AR, M_NOWAIT | M_ZERO);
255     if (!ar_table) {
256         printf("ar: no memory for ATA raid array\n");
257         return 0;
258     }
259     for (array = 0; array < MAX_ARRAYS; array++) {
260         if (!ar_table[array])
261             break;
262     }
263     if (array >= MAX_ARRAYS)
264         return ENOSPC;
265
266     if (!(rdp = (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
267                                          M_NOWAIT | M_ZERO))) {
268         printf("ar%d: failed to allocate raid config storage\n", array);
269         return ENOMEM;
270     }
271
272     for (disk = 0; disk < setup->total_disks; disk++) {
273         if ((atadev = ar_locate_disk(setup->disks[disk]))) {
274             rdp->disks[disk].device = atadev;
275             if (AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) {
276                 setup->disks[disk] = -1;
277                 free(rdp, M_AR);
278                 return EBUSY;
279             }
280
281             switch (rdp->disks[disk].device->channel->chiptype & 0xffff) {
282             case 0x1103:
283                 ctlr |= AR_F_HIGHPOINT_RAID;
284                 rdp->disks[disk].disk_sectors =
285                     AD_SOFTC(rdp->disks[disk])->total_secs;
286                 break;
287
288             default:
289                 ctlr |= AR_F_FREEBSD_RAID;
290                 /* FALLTHROUGH */
291
292             case 0x105a:        
293                 ctlr |= AR_F_PROMISE_RAID;
294                 rdp->disks[disk].disk_sectors =
295                     PR_LBA(AD_SOFTC(rdp->disks[disk]));
296                 break;
297             }
298             if ((rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) &&
299                 (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) !=
300                  (ctlr & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID))) {
301                 free(rdp, M_AR);
302                 return EXDEV;
303             }
304             else
305                 rdp->flags |= ctlr;
306             
307             if (disk_size)
308                 disk_size = min(rdp->disks[disk].disk_sectors, disk_size);
309             else
310                 disk_size = rdp->disks[disk].disk_sectors;
311             rdp->disks[disk].flags = 
312                 (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
313
314             total_disks++;
315         }
316         else {
317             setup->disks[disk] = -1;
318             free(rdp, M_AR);
319             return ENXIO;
320         }
321     }
322     if (!total_disks) {
323         free(rdp, M_AR);
324         return ENODEV;
325     }
326
327     switch (setup->type) {
328     case 1:
329         rdp->flags |= AR_F_RAID0;
330         break;
331     case 2:
332         rdp->flags |= AR_F_RAID1;
333         if (total_disks != 2) {
334             free(rdp, M_AR);
335             return EPERM;
336         }
337         break;
338     case 3:
339         rdp->flags |= (AR_F_RAID0 | AR_F_RAID1);
340         if (total_disks % 2 != 0) {
341             free(rdp, M_AR);
342             return EPERM;
343         }
344         break;
345     case 4:
346         rdp->flags |= AR_F_SPAN;
347         break;
348     }
349
350     for (disk = 0; disk < total_disks; disk++)
351         AD_SOFTC(rdp->disks[disk])->flags = AD_F_RAID_SUBDISK;
352
353     rdp->lun = array;
354     if (rdp->flags & AR_F_RAID0) {
355         int bit = 0;
356
357         while (setup->interleave >>= 1)
358             bit++;
359         if (rdp->flags & AR_F_PROMISE_RAID)
360             rdp->interleave = min(max(2, 1 << bit), 2048);
361         if (rdp->flags & AR_F_HIGHPOINT_RAID)
362             rdp->interleave = min(max(32, 1 << bit), 128);
363     }
364     rdp->total_disks = total_disks;
365     rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1);     
366     rdp->total_sectors = disk_size * rdp->width;
367     rdp->heads = 255;
368     rdp->sectors = 63;
369     rdp->cylinders = rdp->total_sectors / (255 * 63);
370     if (rdp->flags & AR_F_PROMISE_RAID) {
371         rdp->offset = 0;
372         rdp->reserved = 63;
373     }
374     if (rdp->flags & AR_F_HIGHPOINT_RAID) {
375         rdp->offset = HPT_LBA + 1;
376         rdp->reserved = HPT_LBA + 1;
377     }
378     rdp->lock_start = rdp->lock_end = 0xffffffff;
379     rdp->flags |= AR_F_READY;
380
381     ar_table[array] = rdp;
382     ar_attach_raid(rdp, 1);
383     setup->unit = array;
384     return 0;
385 }
386
387 int
388 ata_raid_delete(int array)
389 {
390     struct ar_softc *rdp;
391     int disk;
392
393     if (!ar_table) {
394         printf("ar: no memory for ATA raid array\n");
395         return 0;
396     }
397     if (!(rdp = ar_table[array]))
398         return ENXIO;
399     
400     rdp->flags &= ~AR_F_READY;
401     for (disk = 0; disk < rdp->total_disks; disk++) {
402         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
403             AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
404             ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
405             rdp->disks[disk].flags = 0;
406         }
407     }
408     if (rdp->flags & AR_F_PROMISE_RAID)
409         ar_promise_write_conf(rdp);
410     else
411         ar_highpoint_write_conf(rdp);
412     disk_invalidate(&rdp->disk);
413     disk_destroy(rdp->dev);
414     free(rdp, M_AR);
415     ar_table[array] = NULL;
416     return 0;
417 }
418
419 int
420 ata_raid_status(int array, struct raid_status *status)
421 {
422     struct ar_softc *rdp;
423     int i;
424
425     if (!ar_table || !(rdp = ar_table[array]))
426         return ENXIO;
427
428     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
429     case AR_F_RAID0:
430         status->type = AR_RAID0;
431         break;
432     case AR_F_RAID1:
433         status->type = AR_RAID1;
434         break;
435     case AR_F_RAID0 | AR_F_RAID1:
436         status->type = AR_RAID0 | AR_RAID1;
437         break;
438     case AR_F_SPAN:
439         status->type = AR_SPAN;
440         break;
441     }
442     status->total_disks = rdp->total_disks;
443     for (i = 0; i < rdp->total_disks; i++ ) {
444         if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].device)
445             status->disks[i] = AD_SOFTC(rdp->disks[i])->lun;
446         else
447             status->disks[i] = -1;
448     }
449     status->interleave = rdp->interleave;
450     status->status = 0;
451     if (rdp->flags & AR_F_READY)
452         status->status |= AR_READY;
453     if (rdp->flags & AR_F_DEGRADED)
454         status->status |= AR_DEGRADED;
455     if (rdp->flags & AR_F_REBUILDING) {
456         status->status |= AR_REBUILDING;
457         status->progress = 100*rdp->lock_start/(rdp->total_sectors/rdp->width);
458     }
459     return 0;
460 }
461
462 int
463 ata_raid_rebuild(int array)
464 {
465     struct ar_softc *rdp;
466
467     if (!ar_table || !(rdp = ar_table[array]))
468         return ENXIO;
469     if (rdp->flags & AR_F_REBUILDING)
470         return EBUSY;
471     /* create process here XXX SOS */
472     return ar_rebuild(rdp);
473 }
474
475 static int
476 aropen(dev_t dev, int flags, int fmt, struct thread *td)
477 {
478     struct ar_softc *rdp = dev->si_drv1;
479     struct disklabel *dl;
480         
481     dl = &rdp->disk.d_label;
482     bzero(dl, sizeof *dl);
483     dl->d_secsize = DEV_BSIZE;
484     dl->d_nsectors = rdp->sectors;
485     dl->d_ntracks = rdp->heads;
486     dl->d_ncylinders = rdp->cylinders;
487     dl->d_secpercyl = rdp->sectors * rdp->heads;
488     dl->d_secperunit = rdp->total_sectors;
489     return 0;
490 }
491
492 static void
493 arstrategy(struct buf *bp)
494 {
495     struct ar_softc *rdp = bp->b_dev->si_drv1;
496     int blkno, count, chunk, lba, lbs, tmplba;
497     int drv = 0, change = 0;
498     caddr_t data;
499
500     if (!(rdp->flags & AR_F_READY)) {
501         bp->b_flags |= B_ERROR;
502         bp->b_error = EIO;
503         biodone(bp);
504         return;
505     }
506
507     bp->b_resid = bp->b_bcount;
508     blkno = bp->b_pblkno;
509     data = bp->b_data;
510     for (count = howmany(bp->b_bcount, DEV_BSIZE); count > 0; 
511          count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) {
512         struct ar_buf *buf1, *buf2;
513
514         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
515         case AR_F_SPAN:
516             lba = blkno;
517             while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
518                 lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
519             chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
520                         count);
521             break;
522         
523         case AR_F_RAID0:
524         case AR_F_RAID0 | AR_F_RAID1:
525             tmplba = blkno / rdp->interleave;
526             chunk = blkno % rdp->interleave;
527             if (tmplba == rdp->total_sectors / rdp->interleave) {
528                 lbs = (rdp->total_sectors-(tmplba*rdp->interleave))/rdp->width;
529                 drv = chunk / lbs;
530                 lba = ((tmplba/rdp->width)*rdp->interleave) + chunk%lbs;
531                 chunk = min(count, lbs);
532             }
533             else {
534                 drv = tmplba % rdp->width;
535                 lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
536                 chunk = min(count, rdp->interleave - chunk);
537             }
538             break;
539
540         case AR_F_RAID1:
541             drv = 0;
542             lba = blkno;
543             chunk = count;
544             break;
545
546         default:
547             printf("ar%d: unknown array type in arstrategy\n", rdp->lun);
548             bp->b_flags |= B_ERROR;
549             bp->b_error = EIO;
550             biodone(bp);
551             return;
552         }
553
554         buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO);
555         BUF_LOCKINIT(&buf1->bp);
556         BUF_LOCK(&buf1->bp, LK_EXCLUSIVE);
557         buf1->bp.b_pblkno = lba;
558         if ((buf1->drive = drv) > 0)
559             buf1->bp.b_pblkno += rdp->offset;
560         buf1->bp.b_caller1 = (void *)rdp;
561         buf1->bp.b_bcount = chunk * DEV_BSIZE;
562         buf1->bp.b_data = data;
563         buf1->bp.b_flags = bp->b_flags | B_CALL;
564         buf1->bp.b_iodone = ar_done;
565         buf1->org = bp;
566
567         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
568         case AR_F_SPAN:
569         case AR_F_RAID0:
570             if ((rdp->disks[buf1->drive].flags &
571                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
572                 !AD_SOFTC(rdp->disks[buf1->drive])->dev->si_disk) {
573                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
574                 ar_config_changed(rdp, 1);
575                 free(buf1, M_AR);
576                 bp->b_flags |= B_ERROR;
577                 bp->b_error = EIO;
578                 biodone(bp);
579                 return;
580             }
581             buf1->bp.b_dev = AD_SOFTC(rdp->disks[buf1->drive])->dev;
582             AR_STRATEGY((struct buf *)buf1);
583             break;
584
585         case AR_F_RAID1:
586         case AR_F_RAID0 | AR_F_RAID1:
587             if ((rdp->flags & AR_F_REBUILDING) && !(bp->b_flags & B_READ)) {
588                 if ((bp->b_pblkno >= rdp->lock_start &&
589                      bp->b_pblkno < rdp->lock_end) ||
590                     ((bp->b_pblkno + chunk) > rdp->lock_start &&
591                      (bp->b_pblkno + chunk) <= rdp->lock_end)) {
592                     tsleep(rdp, 0, "arwait", 0);
593                 }
594             }
595             if ((rdp->disks[buf1->drive].flags &
596                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
597                 !AD_SOFTC(rdp->disks[buf1->drive])->dev->si_disk) {
598                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
599                 change = 1;
600             }
601             if ((rdp->disks[buf1->drive + rdp->width].flags &
602                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
603                 !AD_SOFTC(rdp->disks[buf1->drive + rdp->width])->dev->si_disk) {
604                 rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE;
605                 change = 1;
606             }
607             if (change)
608                 ar_config_changed(rdp, 1);
609                 
610             if (!(rdp->flags & AR_F_READY)) {
611                 free(buf1, M_AR);
612                 bp->b_flags |= B_ERROR;
613                 bp->b_error = EIO;
614                 biodone(bp);
615                 return;
616             }
617             if (bp->b_flags & B_READ) {
618                 if ((buf1->bp.b_pblkno <
619                      (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) ||
620                      buf1->bp.b_pblkno >
621                      (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY) ||
622                      !(rdp->disks[buf1->drive].flags & AR_DF_ONLINE)) &&
623                      (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE))
624                         buf1->drive = buf1->drive + rdp->width;
625             }
626             else {
627                 if ((rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE) ||
628                     ((rdp->flags & AR_F_REBUILDING) &&
629                      (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_SPARE) &&
630                      buf1->bp.b_pblkno < rdp->lock_start)) {
631                     if ((rdp->disks[buf1->drive].flags & AR_DF_ONLINE) ||
632                         ((rdp->flags & AR_F_REBUILDING) &&
633                          (rdp->disks[buf1->drive].flags & AR_DF_SPARE) &&
634                          buf1->bp.b_pblkno < rdp->lock_start)) {
635                         buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT);
636                         bcopy(buf1, buf2, sizeof(struct ar_buf));
637                         BUF_LOCKINIT(&buf2->bp);
638                         BUF_LOCK(&buf2->bp, LK_EXCLUSIVE);
639                         buf1->mirror = buf2;
640                         buf2->mirror = buf1;
641                         buf2->drive = buf1->drive + rdp->width;
642                         buf2->bp.b_dev = AD_SOFTC(rdp->disks[buf2->drive])->dev;
643                         AR_STRATEGY((struct buf *)buf2);
644                         rdp->disks[buf2->drive].last_lba =
645                             buf2->bp.b_pblkno + chunk;
646                     }
647                     else
648                         buf1->drive = buf1->drive + rdp->width;
649                 }
650             }
651             buf1->bp.b_dev = AD_SOFTC(rdp->disks[buf1->drive])->dev;
652             AR_STRATEGY((struct buf *)buf1);
653             rdp->disks[buf1->drive].last_lba = buf1->bp.b_pblkno + chunk;
654             break;
655
656         default:
657             printf("ar%d: unknown array type in arstrategy\n", rdp->lun);
658         }
659     }
660 }
661
662 static void
663 ar_done(struct buf *bp)
664 {
665     struct ar_softc *rdp = (struct ar_softc *)bp->b_caller1;
666     struct ar_buf *buf = (struct ar_buf *)bp;
667
668     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
669     case AR_F_SPAN:
670     case AR_F_RAID0:
671         if (buf->bp.b_flags & B_ERROR) {
672             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
673             ar_config_changed(rdp, 1);
674             buf->org->b_flags |= B_ERROR;
675             buf->org->b_error = EIO;
676             biodone(buf->org);
677         }
678         else {
679             buf->org->b_resid -= buf->bp.b_bcount;
680             if (buf->org->b_resid == 0)
681                 biodone(buf->org);
682         }
683         break;
684
685     case AR_F_RAID1:
686     case AR_F_RAID0 | AR_F_RAID1:
687         if (buf->bp.b_flags & B_ERROR) {
688             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
689             ar_config_changed(rdp, 1);
690             if (rdp->flags & AR_F_READY) {
691                 if (buf->bp.b_flags & B_READ) {
692                     if (buf->drive < rdp->width)
693                         buf->drive = buf->drive + rdp->width;
694                     else
695                         buf->drive = buf->drive - rdp->width;
696                     buf->bp.b_dev = AD_SOFTC(rdp->disks[buf->drive])->dev;
697                     buf->bp.b_flags = buf->org->b_flags | B_CALL;
698                     buf->bp.b_error = 0;
699                     AR_STRATEGY((struct buf *)buf);
700                     return;
701                 }
702                 else {
703                     if (buf->flags & AB_F_DONE) {
704                         buf->org->b_resid -= buf->bp.b_bcount;
705                         if (buf->org->b_resid == 0)
706                             biodone(buf->org);
707                     }
708                     else
709                         buf->mirror->flags |= AB_F_DONE;
710                 }
711             }
712             else {
713                 buf->org->b_flags |= B_ERROR;
714                 buf->org->b_error = EIO;
715                 biodone(buf->org);
716             }
717         } 
718         else {
719             if (!(buf->bp.b_flags & B_READ)) {
720                 if (buf->mirror && !(buf->flags & AB_F_DONE)){
721                     buf->mirror->flags |= AB_F_DONE;
722                     break;
723                 }
724             }
725             buf->org->b_resid -= buf->bp.b_bcount;
726             if (buf->org->b_resid == 0)
727                 biodone(buf->org);
728         }
729         break;
730         
731     default:
732         printf("ar%d: unknown array type in ar_done\n", rdp->lun);
733     }
734     free(buf, M_AR);
735 }
736
737 static void
738 ar_config_changed(struct ar_softc *rdp, int writeback)
739 {
740     int disk, flags;
741
742     flags = rdp->flags;
743     rdp->flags |= AR_F_READY;
744     rdp->flags &= ~AR_F_DEGRADED;
745
746     for (disk = 0; disk < rdp->total_disks; disk++)
747         if (!(rdp->disks[disk].flags & AR_DF_PRESENT))
748             rdp->disks[disk].flags &= ~AR_DF_ONLINE;
749
750     for (disk = 0; disk < rdp->total_disks; disk++) {
751         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
752         case AR_F_SPAN:
753         case AR_F_RAID0:
754             if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) {
755                 rdp->flags &= ~AR_F_READY;
756                 printf("ar%d: ERROR - array broken\n", rdp->lun);
757             }
758             break;
759
760         case AR_F_RAID1:
761         case AR_F_RAID0 | AR_F_RAID1:
762             if (disk < rdp->width) {
763                 if (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
764                     !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) {
765                     rdp->flags &= ~AR_F_READY;
766                     printf("ar%d: ERROR - array broken\n", rdp->lun);
767                 }
768                 else if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
769                           !(rdp->disks
770                             [disk + rdp->width].flags & AR_DF_ONLINE))||
771                          (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
772                           (rdp->disks
773                            [disk + rdp->width].flags & AR_DF_ONLINE))) {
774                     rdp->flags |= AR_F_DEGRADED;
775                     if (!(flags & AR_F_DEGRADED))
776                         printf("ar%d: WARNING - mirror lost\n", rdp->lun);
777                 }
778             }
779             break;
780         }
781         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
782             if (rdp->disks[disk].flags & AR_DF_ONLINE)
783                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
784             else
785                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED);
786         }
787     }
788     if (writeback) {
789         if (rdp->flags & AR_F_PROMISE_RAID)
790             ar_promise_write_conf(rdp);
791         if (rdp->flags & AR_F_HIGHPOINT_RAID)
792             ar_highpoint_write_conf(rdp);
793     }
794 }
795
796 static int
797 ar_rebuild(struct ar_softc *rdp)
798 {
799     int disk, s, count = 0, error = 0;
800     caddr_t buffer;
801
802     if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED))
803         return EEXIST;
804
805     for (disk = 0; disk < rdp->total_disks; disk++) {
806         if (((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
807              (AR_DF_PRESENT | AR_DF_SPARE)) && rdp->disks[disk].device) {
808             if (AD_SOFTC(rdp->disks[disk])->total_secs <
809                 rdp->disks[disk].disk_sectors) {
810                 ata_prtdev(rdp->disks[disk].device,
811                            "disk capacity too small for this RAID config\n");
812 #if 0
813                 rdp->disks[disk].flags &= ~AR_DF_SPARE;
814                 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
815 #endif
816                 continue;
817             }
818             ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE);
819             count++;
820         }
821     }
822     if (!count)
823         return ENODEV;
824
825     /* setup start conditions */
826     s = splbio();
827     rdp->lock_start = 0;
828     rdp->lock_end = rdp->lock_start + 256;
829     rdp->flags |= AR_F_REBUILDING;
830     splx(s);
831     buffer = malloc(256 * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO);
832
833     /* now go copy entire disk(s) */
834     while (rdp->lock_end < (rdp->total_sectors / rdp->width)) {
835         int size = min(256, (rdp->total_sectors / rdp->width) - rdp->lock_end);
836
837         for (disk = 0; disk < rdp->width; disk++) {
838             struct ad_softc *adp;
839
840             if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
841                  (rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) ||
842                 ((rdp->disks[disk].flags & AR_DF_ONLINE) && 
843                  !(rdp->disks[disk + rdp->width].flags & AR_DF_SPARE)) ||
844                 ((rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) &&
845                  !(rdp->disks[disk].flags & AR_DF_SPARE)))
846                 continue;
847
848             if (rdp->disks[disk].flags & AR_DF_ONLINE)
849                 adp = AD_SOFTC(rdp->disks[disk]);
850             else
851                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
852             if ((error = ar_rw(adp, rdp->lock_start,
853                                size * DEV_BSIZE, buffer, AR_READ | AR_WAIT)))
854                 break;
855
856             if (rdp->disks[disk].flags & AR_DF_ONLINE)
857                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
858             else
859                 adp = AD_SOFTC(rdp->disks[disk]);
860             if ((error = ar_rw(adp, rdp->lock_start,
861                                size * DEV_BSIZE, buffer, AR_WRITE | AR_WAIT)))
862                 break;
863         }
864         if (error) {
865             wakeup(rdp);
866             free(buffer, M_AR);
867             return error;
868         }
869         s = splbio();
870         rdp->lock_start = rdp->lock_end;
871         rdp->lock_end = rdp->lock_start + size;
872         splx(s);
873         wakeup(rdp);
874     }
875     free(buffer, M_AR);
876     for (disk = 0; disk < rdp->total_disks; disk++) {
877         if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
878             (AR_DF_PRESENT | AR_DF_SPARE)) {
879             rdp->disks[disk].flags &= ~AR_DF_SPARE;
880             rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE);
881         }
882     }
883     s = splbio();
884     rdp->lock_start = 0xffffffff;
885     rdp->lock_end = 0xffffffff;
886     rdp->flags &= ~AR_F_REBUILDING;
887     splx(s);
888     ar_config_changed(rdp, 1);
889     return 0;
890 }
891
892 static int
893 ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
894 {
895     struct highpoint_raid_conf *info;
896     struct ar_softc *raid = NULL;
897     int array, disk_number = 0, retval = 0;
898
899     if (!(info = (struct highpoint_raid_conf *)
900           malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
901         return retval;
902
903     if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
904               (caddr_t)info, AR_READ | AR_WAIT)) {
905         if (bootverbose)
906             printf("ar: HighPoint read conf failed\n");
907         goto highpoint_out;
908     }
909
910     /* check if this is a HighPoint RAID struct */
911     if (info->magic != HPT_MAGIC_OK && info->magic != HPT_MAGIC_BAD) {
912         if (bootverbose)
913             printf("ar: HighPoint check1 failed\n");
914         goto highpoint_out;
915     }
916
917     /* is this disk defined, or an old leftover/spare ? */
918     if (!info->magic_0) {
919         if (bootverbose)
920             printf("ar: HighPoint check2 failed\n");
921         goto highpoint_out;
922     }
923
924     /* now convert HighPoint config info into our generic form */
925     for (array = 0; array < MAX_ARRAYS; array++) {
926         if (!raidp[array]) {
927             raidp[array] = 
928                 (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
929                                          M_NOWAIT | M_ZERO);
930             if (!raidp[array]) {
931                 printf("ar%d: failed to allocate raid config storage\n", array);
932                 goto highpoint_out;
933             }
934         }
935         raid = raidp[array];
936         if (raid->flags & AR_F_PROMISE_RAID)
937             continue;
938
939         switch (info->type) {
940         case HPT_T_RAID0:
941             if ((info->order & (HPT_O_RAID0|HPT_O_OK))==(HPT_O_RAID0|HPT_O_OK))
942                 goto highpoint_raid1;
943             if (info->order & (HPT_O_RAID0 | HPT_O_RAID1))
944                 goto highpoint_raid01;
945             if (raid->magic_0 && raid->magic_0 != info->magic_0)
946                 continue;
947             raid->magic_0 = info->magic_0;
948             raid->flags |= AR_F_RAID0;
949             raid->interleave = 1 << info->stripe_shift;
950             disk_number = info->disk_number;
951             if (!(info->order & HPT_O_OK))
952                 info->magic = 0;        /* mark bad */
953             break;
954
955         case HPT_T_RAID1:
956 highpoint_raid1:
957             if (raid->magic_0 && raid->magic_0 != info->magic_0)
958                 continue;
959             raid->magic_0 = info->magic_0;
960             raid->flags |= AR_F_RAID1;
961             disk_number = (info->disk_number > 0);
962             break;
963
964         case HPT_T_RAID01_RAID0:
965 highpoint_raid01:
966             if (info->order & HPT_O_RAID0) {
967                 if ((raid->magic_0 && raid->magic_0 != info->magic_0) ||
968                     (raid->magic_1 && raid->magic_1 != info->magic_1))
969                     continue;
970                 raid->magic_0 = info->magic_0;
971                 raid->magic_1 = info->magic_1;
972                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
973                 raid->interleave = 1 << info->stripe_shift;
974                 disk_number = info->disk_number;
975             }
976             else {
977                 if (raid->magic_1 && raid->magic_1 != info->magic_1)
978                     continue;
979                 raid->magic_1 = info->magic_1;
980                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
981                 raid->interleave = 1 << info->stripe_shift;
982                 disk_number = info->disk_number + info->array_width;
983                 if (!(info->order & HPT_O_RAID1))
984                     info->magic = 0;    /* mark bad */
985             }
986             break;
987
988         case HPT_T_SPAN:
989             if (raid->magic_0 && raid->magic_0 != info->magic_0)
990                 continue;
991             raid->magic_0 = info->magic_0;
992             raid->flags |= AR_F_SPAN;
993             disk_number = info->disk_number;
994             break;
995
996         default:
997             printf("ar%d: HighPoint unknown RAID type 0x%02x\n",
998                    array, info->type);
999             goto highpoint_out;
1000         }
1001
1002         raid->flags |= AR_F_HIGHPOINT_RAID;
1003         raid->disks[disk_number].device = adp->device;
1004         raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED);
1005         raid->lun = array;
1006         if (info->magic == HPT_MAGIC_OK) {
1007             raid->disks[disk_number].flags |= AR_DF_ONLINE;
1008             raid->flags |= AR_F_READY;
1009             raid->width = info->array_width;
1010             raid->heads = 255;
1011             raid->sectors = 63;
1012             raid->cylinders = info->total_sectors / (63 * 255);
1013             raid->total_sectors = info->total_sectors;
1014             raid->offset = HPT_LBA + 1;
1015             raid->reserved = HPT_LBA + 1;
1016             raid->lock_start = raid->lock_end = info->rebuild_lba;
1017             raid->disks[disk_number].disk_sectors =
1018                 info->total_sectors / info->array_width;
1019         }
1020         else
1021             raid->disks[disk_number].flags &= ~ AR_DF_ONLINE;
1022
1023         if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width))
1024             raid->total_disks = raid->width;
1025         if (disk_number >= raid->total_disks)
1026             raid->total_disks = disk_number + 1;
1027         retval = 1;
1028         break;
1029     }
1030 highpoint_out:
1031     free(info, M_AR);
1032     return retval;
1033 }
1034
1035 static int
1036 ar_highpoint_write_conf(struct ar_softc *rdp)
1037 {
1038     struct highpoint_raid_conf *config;
1039     struct timeval timestamp;
1040     int disk;
1041
1042     microtime(&timestamp);
1043     rdp->magic_0 = timestamp.tv_sec + 2;
1044     rdp->magic_1 = timestamp.tv_sec;
1045    
1046     for (disk = 0; disk < rdp->total_disks; disk++) {
1047         if (!(config = (struct highpoint_raid_conf *)
1048               malloc(sizeof(struct highpoint_raid_conf),
1049                      M_AR, M_NOWAIT | M_ZERO))) {
1050             printf("ar%d: Highpoint write conf failed\n", rdp->lun);
1051             return -1;
1052         }
1053         if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
1054             (AR_DF_PRESENT | AR_DF_ONLINE))
1055             config->magic = HPT_MAGIC_OK;
1056         if (rdp->disks[disk].flags & AR_DF_ASSIGNED) {
1057             config->magic_0 = rdp->magic_0;
1058             strcpy(config->name_1, "FreeBSD");
1059         }
1060         config->disk_number = disk;
1061
1062         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1063         case AR_F_RAID0:
1064             config->type = HPT_T_RAID0;
1065             strcpy(config->name_2, "RAID 0");
1066             if (rdp->disks[disk].flags & AR_DF_ONLINE)
1067                 config->order = HPT_O_OK;
1068             break;
1069
1070         case AR_F_RAID1:
1071             config->type = HPT_T_RAID0; /* bogus but old HPT BIOS need it */
1072             strcpy(config->name_2, "RAID 1");
1073             config->disk_number = (disk < rdp->width) ? disk : disk + 5;
1074             config->order = HPT_O_RAID0 | HPT_O_OK;
1075             break;
1076
1077         case AR_F_RAID0 | AR_F_RAID1:
1078             config->type = HPT_T_RAID01_RAID0;
1079             strcpy(config->name_2, "RAID 0+1");
1080             if (rdp->disks[disk].flags & AR_DF_ONLINE) {
1081                 if (disk < rdp->width) {
1082                     config->order = (HPT_O_RAID0 | HPT_O_RAID1);
1083                     config->magic_0 = rdp->magic_0 - 1;
1084                 }
1085                 else {
1086                     config->order = HPT_O_RAID1;
1087                     config->disk_number -= rdp->width;
1088                 }
1089             }
1090             else
1091                 config->magic_0 = rdp->magic_0 - 1;
1092             config->magic_1 = rdp->magic_1;
1093             break;
1094
1095         case AR_F_SPAN:
1096             config->type = HPT_T_SPAN;
1097             strcpy(config->name_2, "SPAN");
1098             break;
1099         }
1100
1101         config->array_width = rdp->width;
1102         config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0;
1103         config->total_sectors = rdp->total_sectors;
1104         config->rebuild_lba = rdp->lock_start;
1105
1106         if ((rdp->disks[disk].device && rdp->disks[disk].device->driver) &&
1107             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1108
1109             if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA,
1110                       sizeof(struct highpoint_raid_conf),
1111                       (caddr_t)config, AR_WRITE)) {
1112                 printf("ar%d: Highpoint write conf failed\n", rdp->lun);
1113                 return -1;
1114             }
1115         }
1116     }
1117     return 0;
1118 }
1119
1120 static int
1121 ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
1122 {
1123     struct promise_raid_conf *info;
1124     struct ar_softc *raid;
1125     u_int32_t magic, cksum, *ckptr;
1126     int array, count, disk, disksum = 0, retval = 0; 
1127
1128     if (!(info = (struct promise_raid_conf *)
1129           malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
1130         return retval;
1131
1132     if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
1133               (caddr_t)info, AR_READ | AR_WAIT)) {
1134         if (bootverbose)
1135             printf("ar: %s read conf failed\n", local ? "FreeBSD" : "Promise");
1136         goto promise_out;
1137     }
1138
1139     /* check if this is a Promise RAID struct (or our local one) */
1140     if (local) {
1141         if (strncmp(info->promise_id, ATA_MAGIC, sizeof(ATA_MAGIC))) {
1142             if (bootverbose)
1143                 printf("ar: FreeBSD check1 failed\n");
1144             goto promise_out;
1145         }
1146     }
1147     else {
1148         if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) {
1149             if (bootverbose)
1150                 printf("ar: Promise check1 failed\n");
1151             goto promise_out;
1152         }
1153     }
1154
1155     /* check if the checksum is OK */
1156     for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++)
1157         cksum += *ckptr++;
1158     if (cksum != *ckptr) {  
1159         if (bootverbose)
1160             printf("ar: %s check2 failed\n", local ? "FreeBSD" : "Promise");         
1161         goto promise_out;
1162     }
1163
1164     /* now convert Promise config info into our generic form */
1165     if (info->raid.integrity != PR_I_VALID) {
1166         if (bootverbose)
1167             printf("ar: %s check3 failed\n", local ? "FreeBSD" : "Promise");         
1168         goto promise_out;
1169     }
1170
1171     for (array = 0; array < MAX_ARRAYS; array++) {
1172         if (!raidp[array]) {
1173             raidp[array] = 
1174                 (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
1175                                          M_NOWAIT | M_ZERO);
1176             if (!raidp[array]) {
1177                 printf("ar%d: failed to allocate raid config storage\n", array);
1178                 goto promise_out;
1179             }
1180         }
1181         raid = raidp[array];
1182         if (raid->flags & AR_F_HIGHPOINT_RAID)
1183             continue;
1184
1185         magic = (adp->device->channel->chiptype >> 16) |
1186                 (info->raid.array_number << 16);
1187
1188         if ((raid->flags & AR_F_PROMISE_RAID) && magic != raid->magic_0)
1189             continue;
1190
1191         /* update our knowledge about the array config based on generation */
1192         if (!info->raid.generation || info->raid.generation > raid->generation){
1193             raid->generation = info->raid.generation;
1194             raid->flags = AR_F_PROMISE_RAID;
1195             if (local)
1196                 raid->flags |= AR_F_FREEBSD_RAID;
1197             raid->magic_0 = magic;
1198             raid->lun = array;
1199             if ((info->raid.status &
1200                  (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) ==
1201                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) {
1202                 raid->flags |= AR_F_READY;
1203                 if (info->raid.status & PR_S_DEGRADED)
1204                     raid->flags |= AR_F_DEGRADED;
1205             }
1206             else
1207                 raid->flags &= ~AR_F_READY;
1208
1209             switch (info->raid.type) {
1210             case PR_T_RAID0:
1211                 raid->flags |= AR_F_RAID0;
1212                 break;
1213
1214             case PR_T_RAID1:
1215                 raid->flags |= AR_F_RAID1;
1216                 if (info->raid.array_width > 1)
1217                     raid->flags |= AR_F_RAID0;
1218                 break;
1219
1220             case PR_T_SPAN:
1221                 raid->flags |= AR_F_SPAN;
1222                 break;
1223
1224             default:
1225                 printf("ar%d: %s unknown RAID type 0x%02x\n",
1226                        array, local ? "FreeBSD" : "Promise", info->raid.type);
1227                 goto promise_out;
1228             }
1229             raid->interleave = 1 << info->raid.stripe_shift;
1230             raid->width = info->raid.array_width;
1231             raid->total_disks = info->raid.total_disks;
1232             raid->heads = info->raid.heads + 1;
1233             raid->sectors = info->raid.sectors;
1234             raid->cylinders = info->raid.cylinders + 1;
1235             raid->total_sectors = info->raid.total_sectors;
1236             raid->offset = 0;
1237             raid->reserved = 63;
1238             raid->lock_start = raid->lock_end = info->raid.rebuild_lba;
1239
1240             /* convert disk flags to our internal types */
1241             for (disk = 0; disk < info->raid.total_disks; disk++) {
1242                 raid->disks[disk].flags = 0;
1243                 disksum += info->raid.disk[disk].flags;
1244                 if (info->raid.disk[disk].flags & PR_F_ONLINE)
1245                     raid->disks[disk].flags |= AR_DF_ONLINE;
1246                 if (info->raid.disk[disk].flags & PR_F_ASSIGNED)
1247                     raid->disks[disk].flags |= AR_DF_ASSIGNED;
1248                 if (info->raid.disk[disk].flags & PR_F_SPARE) {
1249                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
1250                     raid->disks[disk].flags |= AR_DF_SPARE;
1251                 }
1252                 if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN))
1253                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
1254             }
1255             if (!disksum) {
1256                 free(raidp[array], M_AR);
1257                 raidp[array] = NULL;
1258                 goto promise_out;
1259             }
1260         }
1261         if (raid->disks[info->raid.disk_number].flags && adp->device) {
1262             raid->disks[info->raid.disk_number].device = adp->device;
1263             raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT;
1264             raid->disks[info->raid.disk_number].disk_sectors =
1265                 info->raid.total_sectors / info->raid.array_width;
1266                 /*info->raid.disk_sectors;*/
1267             retval = 1;
1268         }
1269         break;
1270     }
1271 promise_out:
1272     free(info, M_AR);
1273     return retval;
1274 }
1275
1276 static int
1277 ar_promise_write_conf(struct ar_softc *rdp)
1278 {
1279     struct promise_raid_conf *config;
1280     struct timeval timestamp;
1281     u_int32_t *ckptr;
1282     int count, disk, drive;
1283     int local = rdp->flags & AR_F_FREEBSD_RAID;
1284
1285     rdp->generation++;
1286     microtime(&timestamp);
1287
1288     for (disk = 0; disk < rdp->total_disks; disk++) {
1289         if (!(config = (struct promise_raid_conf *)
1290               malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) {
1291             printf("ar%d: %s write conf failed\n",
1292                    rdp->lun, local ? "FreeBSD" : "Promise");
1293             return -1;
1294         }
1295         for (count = 0; count < sizeof(struct promise_raid_conf); count++)
1296             *(((u_int8_t *)config) + count) = 255 - (count % 256);
1297
1298         if (local)
1299             bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC));
1300         else
1301             bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC));
1302         config->dummy_0 = 0x00020000;
1303         config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec;
1304         config->magic_1 = timestamp.tv_sec >> 16;
1305         config->magic_2 = timestamp.tv_sec;
1306         config->raid.integrity = PR_I_VALID;
1307
1308         config->raid.disk_number = disk;
1309         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
1310             config->raid.channel = rdp->disks[disk].device->channel->unit;
1311             config->raid.device = (rdp->disks[disk].device->unit != 0);
1312             if (AD_SOFTC(rdp->disks[disk])->dev->si_disk)
1313                 config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk]));
1314             /*config->raid.disk_offset*/
1315         }
1316         config->raid.magic_0 = config->magic_0;
1317         config->raid.rebuild_lba = rdp->lock_start;
1318         config->raid.generation = rdp->generation;
1319
1320         if (rdp->flags & AR_F_READY) {
1321             config->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE);
1322             config->raid.status = 
1323                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY);
1324             if (rdp->flags & AR_F_DEGRADED)
1325                 config->raid.status |= PR_S_DEGRADED;
1326             else
1327                 config->raid.status |= PR_S_FUNCTIONAL;
1328         }
1329         else {
1330             config->raid.status = 0;
1331             config->raid.flags = PR_F_DOWN;
1332         }
1333
1334         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1335         case AR_F_RAID0:
1336             config->raid.type = PR_T_RAID0;
1337             break;
1338         case AR_F_RAID1:
1339             config->raid.type = PR_T_RAID1;
1340             break;
1341         case AR_F_RAID0 | AR_F_RAID1:
1342             config->raid.type = PR_T_RAID1;
1343             break;
1344         case AR_F_SPAN:
1345             config->raid.type = PR_T_SPAN;
1346             break;
1347         }
1348
1349         config->raid.total_disks = rdp->total_disks;
1350         config->raid.stripe_shift = ffs(rdp->interleave) - 1;
1351         config->raid.array_width = rdp->width;
1352         config->raid.array_number = rdp->lun;
1353         config->raid.total_sectors = rdp->total_sectors;
1354         config->raid.cylinders = rdp->cylinders - 1;
1355         config->raid.heads = rdp->heads - 1;
1356         config->raid.sectors = rdp->sectors;
1357         config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1;
1358
1359         bzero(&config->raid.disk, 8 * 12);
1360         for (drive = 0; drive < rdp->total_disks; drive++) {
1361             config->raid.disk[drive].flags = 0;
1362             if (rdp->disks[drive].flags & AR_DF_PRESENT)
1363                 config->raid.disk[drive].flags |= PR_F_VALID;
1364             if (rdp->disks[drive].flags & AR_DF_ASSIGNED)
1365                 config->raid.disk[drive].flags |= PR_F_ASSIGNED;
1366             if (rdp->disks[drive].flags & AR_DF_ONLINE)
1367                 config->raid.disk[drive].flags |= PR_F_ONLINE;
1368             else
1369                 if (rdp->disks[drive].flags & AR_DF_PRESENT)
1370                     config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN);
1371             if (rdp->disks[drive].flags & AR_DF_SPARE)
1372                 config->raid.disk[drive].flags |= PR_F_SPARE;
1373             config->raid.disk[drive].dummy_0 = 0x0;
1374             if (rdp->disks[drive].device) {
1375                 config->raid.disk[drive].channel =
1376                     rdp->disks[drive].device->channel->unit;
1377                 config->raid.disk[drive].device =
1378                     (rdp->disks[drive].device->unit != 0);
1379             }
1380             config->raid.disk[drive].magic_0 =
1381                 PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec;
1382         }
1383
1384         config->checksum = 0;
1385         for (ckptr = (int32_t *)config, count = 0; count < 511; count++)
1386             config->checksum += *ckptr++;
1387         if (rdp->disks[disk].device && rdp->disks[disk].device->driver &&
1388             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1389             if (ar_rw(AD_SOFTC(rdp->disks[disk]),
1390                       PR_LBA(AD_SOFTC(rdp->disks[disk])),
1391                       sizeof(struct promise_raid_conf),
1392                       (caddr_t)config, AR_WRITE)) {
1393                 printf("ar%d: %s write conf failed\n",
1394                        rdp->lun, local ? "FreeBSD" : "Promise");
1395                 return -1;
1396             }
1397         }
1398     }
1399     return 0;
1400 }
1401
1402 static void
1403 ar_rw_done(struct buf *bp)
1404 {
1405     free(bp->b_data, M_AR);
1406     free(bp, M_AR);
1407 }
1408
1409 static int
1410 ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags)
1411 {
1412     struct buf *bp;
1413     int retry = 0, error = 0;
1414
1415     if (!(bp = (struct buf *)malloc(sizeof(struct buf), M_AR, M_NOWAIT|M_ZERO)))
1416         return ENOMEM;
1417     BUF_LOCKINIT(bp);
1418     BUF_LOCK(bp, LK_EXCLUSIVE);
1419     bp->b_dev = adp->dev;
1420     bp->b_data = data;
1421     bp->b_pblkno = lba;
1422     bp->b_bcount = count;
1423     if (flags & AR_WAIT)
1424         bp->b_iodone = (void *)wakeup;
1425     else
1426         bp->b_iodone = ar_rw_done;
1427     bp->b_flags = B_CALL;
1428     if (flags & AR_READ)
1429         bp->b_flags |= B_READ;
1430     if (flags & AR_WRITE)
1431         bp->b_flags |= B_WRITE;
1432
1433     AR_STRATEGY((struct buf *)bp);
1434
1435     if (flags & AR_WAIT) {
1436         while ((retry++ < (15*hz/10)) && (error = !(bp->b_flags & B_DONE)))
1437             error = tsleep(bp, 0, "arrw", 10);
1438         if (!error && (bp->b_flags & B_ERROR))
1439             error = bp->b_error;
1440         free(bp, M_AR);
1441     }
1442     return error;
1443 }
1444
1445 static struct ata_device *
1446 ar_locate_disk(int diskno)
1447 {
1448     struct ata_channel *ch;
1449     int ctlr;
1450
1451     for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
1452         if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
1453             continue;
1454         if (ch->devices & ATA_ATA_MASTER)
1455             if (ch->device[MASTER].driver &&
1456                 ((struct ad_softc *)(ch->device[MASTER].driver))->lun == diskno)
1457                 return &ch->device[MASTER];
1458         if (ch->devices & ATA_ATA_SLAVE)
1459             if (ch->device[SLAVE].driver &&
1460                 ((struct ad_softc *)(ch->device[SLAVE].driver))->lun == diskno)
1461                 return &ch->device[SLAVE];
1462     }
1463     return NULL;
1464 }