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