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