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