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