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