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