kernel - Major MPSAFE Infrastructure
[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.26 2007/05/15 00:01:03 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 <sys/rman.h>
45 #include <sys/proc.h>
46 #include <sys/buf2.h>
47 #include <sys/thread2.h>
48
49 #include "ata-all.h"
50 #include "ata-disk.h"
51 #include "ata-raid.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_config_changed(struct ar_softc *, int);
70 static int ar_rebuild(struct ar_softc *);
71 static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **);
72 static int ar_highpoint_write_conf(struct ar_softc *);
73 static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int);
74 static int ar_promise_write_conf(struct ar_softc *);
75 static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int);
76 static struct ata_device *ar_locate_disk(int);
77
78 /* internal vars */
79 static struct ar_softc **ar_table = NULL;
80 static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver");
81
82 int
83 ata_raiddisk_attach(struct ad_softc *adp)
84 {
85     struct ar_softc *rdp;
86     int array, disk;
87
88     if (ar_table) {
89         for (array = 0; array < MAX_ARRAYS; array++) {
90             if (!(rdp = ar_table[array]) || !rdp->flags)
91                 continue;
92    
93             for (disk = 0; disk < rdp->total_disks; disk++) {
94                 if ((rdp->disks[disk].flags & AR_DF_ASSIGNED) &&
95                     rdp->disks[disk].device == adp->device) {
96                     ata_prtdev(rdp->disks[disk].device,
97                                "inserted into ar%d disk%d as spare\n",
98                                array, disk);
99                     rdp->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE);
100                     AD_SOFTC(rdp->disks[disk])->flags = AD_F_RAID_SUBDISK;
101                     ar_config_changed(rdp, 1);
102                     return 1;
103                 }
104             }
105         }
106     }
107
108     if (!ar_table) {
109         ar_table = kmalloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
110                           M_AR, M_WAITOK | M_ZERO);
111     }
112
113     switch(adp->device->channel->chiptype) {
114     case 0x4d33105a: case 0x4d38105a: case 0x4d30105a:
115     case 0x0d30105a: case 0x4d68105a: case 0x6268105a:
116     case 0x4d69105a: case 0x5275105a: case 0x6269105a:
117     case 0x7275105a:
118         /* test RAID bit in PCI reg XXX */
119         return (ar_promise_read_conf(adp, ar_table, 0));
120
121     case 0x00041103: case 0x00051103: case 0x00081103:
122         return (ar_highpoint_read_conf(adp, ar_table));
123
124     default:
125         return (ar_promise_read_conf(adp, ar_table, 1));
126     }
127     return 0;
128 }
129
130 int
131 ata_raiddisk_detach(struct ad_softc *adp)
132 {
133     struct ar_softc *rdp;
134     int array, disk;
135
136     if (ar_table) {
137         for (array = 0; array < MAX_ARRAYS; array++) {
138             if (!(rdp = ar_table[array]) || !rdp->flags)
139                 continue; 
140             for (disk = 0; disk < rdp->total_disks; disk++) {
141                 if (rdp->disks[disk].device == adp->device) {
142                     ata_prtdev(rdp->disks[disk].device,
143                                "deleted from ar%d disk%d\n", array, disk);
144                     rdp->disks[disk].flags &= ~(AR_DF_PRESENT | AR_DF_ONLINE);
145                     AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
146                     ar_config_changed(rdp, 1);
147                     return 1;
148                 }
149             }
150         }
151     }
152     return 0;
153 }
154
155 void
156 ata_raid_attach()
157 {
158     struct ar_softc *rdp;
159     int array;
160
161     if (!ar_table)
162         return;
163
164     for (array = 0; array < MAX_ARRAYS; array++) {
165         if (!(rdp = ar_table[array]) || !rdp->flags)
166             continue;
167         ar_attach_raid(rdp, 0);
168     }
169 }
170
171 static void
172 ar_attach_raid(struct ar_softc *rdp, int update)
173 {
174         struct disk_info info;
175     cdev_t dev;
176     int disk;
177
178     ar_config_changed(rdp, update);
179     dev = disk_create(rdp->lun, &rdp->disk, &ar_ops);
180     dev->si_drv1 = rdp;
181     dev->si_iosize_max = 256 * DEV_BSIZE;
182     rdp->dev = dev;
183
184         /*
185          * Set disk info, as it appears that all needed data is available already.
186          * Setting the disk info will also cause the probing to start.
187          */
188     bzero(&info, sizeof(info));
189     info.d_media_blksize = DEV_BSIZE;           /* mandatory */
190     info.d_media_blocks = rdp->total_sectors;
191
192     info.d_secpertrack = rdp->sectors;          /* optional */
193     info.d_nheads = rdp->heads;
194     info.d_ncylinders = rdp->cylinders;
195     info.d_secpercyl = rdp->sectors * rdp->heads;
196
197     kprintf("ar%d: %lluMB <ATA ", rdp->lun, (unsigned long long)
198            (rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE)));
199     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
200     case AR_F_RAID0:
201         kprintf("RAID0 "); break;
202     case AR_F_RAID1:
203         kprintf("RAID1 "); break;
204     case AR_F_SPAN:
205         kprintf("SPAN "); break;
206     case (AR_F_RAID0 | AR_F_RAID1):
207         kprintf("RAID0+1 "); break;
208     default:
209         kprintf("unknown 0x%x> ", rdp->flags);
210         return;
211     }
212     kprintf("array> [%d/%d/%d] status: ",
213            rdp->cylinders, rdp->heads, rdp->sectors);
214     switch (rdp->flags & (AR_F_DEGRADED | AR_F_READY)) {
215     case AR_F_READY:
216         kprintf("READY");
217         break;
218     case (AR_F_DEGRADED | AR_F_READY):
219         kprintf("DEGRADED");
220         break;
221     default:
222         kprintf("BROKEN");
223         break;
224     }
225     kprintf(" subdisks:\n");
226     for (disk = 0; disk < rdp->total_disks; disk++) {
227         if (rdp->disks[disk].flags & AR_DF_PRESENT) {
228             if (rdp->disks[disk].flags & AR_DF_ONLINE)
229                 kprintf(" %d READY ", disk);
230             else if (rdp->disks[disk].flags & AR_DF_SPARE)
231                 kprintf(" %d SPARE ", disk);
232             else
233                 kprintf(" %d FREE  ", disk);
234             ad_print(AD_SOFTC(rdp->disks[disk]));
235             kprintf("         ");
236             ata_enclosure_print(AD_SOFTC(rdp->disks[disk])->device);
237         }
238         else if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
239             kprintf(" %d DOWN\n", disk);
240         else
241             kprintf(" %d INVALID no RAID config info on this disk\n", disk);
242     }
243     disk_setdiskinfo(&rdp->disk, &info);
244 }
245
246 int
247 ata_raid_create(struct raid_setup *setup)
248 {
249     struct ata_device *atadev;
250     struct ar_softc *rdp;
251     int array, disk;
252     int ctlr = 0, disk_size = 0, total_disks = 0;
253
254     if (!ar_table) {
255         ar_table = kmalloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
256                           M_AR, M_WAITOK | M_ZERO);
257     }
258     for (array = 0; array < MAX_ARRAYS; array++) {
259         if (!ar_table[array])
260             break;
261     }
262     if (array >= MAX_ARRAYS)
263         return ENOSPC;
264
265     rdp = kmalloc(sizeof(struct ar_softc), M_AR, M_WAITOK | M_ZERO);
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                 kfree(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                 kfree(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             kfree(rdp, M_AR);
314             return ENXIO;
315         }
316     }
317     if (!total_disks) {
318         kfree(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             kfree(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             kfree(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         kprintf("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->disk);
409     kfree(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(struct dev_open_args *ap)
472 {
473 #if 0
474     struct ar_softc *rdp = ap->a_head.a_dev->si_drv1;
475     struct disk_info info;
476
477     bzero(&info, sizeof(info));
478     info.d_media_blksize = DEV_BSIZE;           /* mandatory */
479     info.d_media_blocks = rdp->total_sectors;
480
481     info.d_secpertrack = rdp->sectors;          /* optional */
482     info.d_nheads = rdp->heads;
483     info.d_ncylinders = rdp->cylinders;
484     info.d_secpercyl = rdp->sectors * rdp->heads;
485     disk_setdiskinfo(&rdp->disk, &info);
486     return 0;
487 #endif
488 }
489
490 static int
491 arstrategy(struct dev_strategy_args *ap)
492 {
493     cdev_t dev = ap->a_head.a_dev;
494     struct bio *bio = ap->a_bio;
495     struct buf *bp = bio->bio_buf;
496     struct ar_softc *rdp = dev->si_drv1;
497     int blkno, count, chunk, lba, lbs, tmplba;
498     int orig_blkno;
499     int buf1_blkno;
500     int drv = 0, change = 0;
501     caddr_t data;
502
503     if (!(rdp->flags & AR_F_READY)) {
504         bp->b_flags |= B_ERROR;
505         bp->b_error = EIO;
506         biodone(bio);
507         return(0);
508     }
509
510     KKASSERT((bio->bio_offset & DEV_BMASK) == 0);
511
512     bp->b_resid = bp->b_bcount;
513     blkno = (int)(bio->bio_offset >> DEV_BSHIFT);
514     orig_blkno = blkno;
515     data = bp->b_data;
516
517     for (count = howmany(bp->b_bcount, DEV_BSIZE); count > 0; 
518          count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) {
519         struct ar_buf *buf1, *buf2;
520
521         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
522         case AR_F_SPAN:
523             lba = blkno;
524             while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
525                 lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
526             chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
527                         count);
528             break;
529         
530         case AR_F_RAID0:
531         case AR_F_RAID0 | AR_F_RAID1:
532             tmplba = blkno / rdp->interleave;
533             chunk = blkno % rdp->interleave;
534             if (tmplba == rdp->total_sectors / rdp->interleave) {
535                 lbs = (rdp->total_sectors-(tmplba*rdp->interleave))/rdp->width;
536                 drv = chunk / lbs;
537                 lba = ((tmplba/rdp->width)*rdp->interleave) + chunk%lbs;
538                 chunk = min(count, lbs);
539             }
540             else {
541                 drv = tmplba % rdp->width;
542                 lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
543                 chunk = min(count, rdp->interleave - chunk);
544             }
545             break;
546
547         case AR_F_RAID1:
548             drv = 0;
549             lba = blkno;
550             chunk = count;
551             break;
552
553         default:
554             kprintf("ar%d: unknown array type in arstrategy\n", rdp->lun);
555             bp->b_flags |= B_ERROR;
556             bp->b_error = EIO;
557             biodone(bio);
558             return(0);
559         }
560
561         buf1 = kmalloc(sizeof(struct ar_buf), M_AR, M_INTWAIT | M_ZERO);
562         BUF_LOCKINIT(&buf1->bp);
563         BUF_LOCK(&buf1->bp, LK_EXCLUSIVE);
564         initbufbio(&buf1->bp);
565         buf1->bp.b_bio1.bio_offset = (off_t)lba << DEV_BSHIFT;
566         if ((buf1->drive = drv) > 0)
567             buf1->bp.b_bio1.bio_offset += (off_t)rdp->offset << DEV_BSHIFT;
568         buf1->bp.b_bio1.bio_caller_info1.ptr = (void *)rdp;
569         buf1->bp.b_bcount = chunk * DEV_BSIZE;
570         buf1->bp.b_data = data;
571         buf1->bp.b_flags = bp->b_flags | B_PAGING;
572         buf1->bp.b_cmd = bp->b_cmd;
573         buf1->bp.b_bio1.bio_done = ar_done;
574         buf1->org = bio;
575         buf1_blkno = (int)(buf1->bp.b_bio1.bio_offset >> DEV_BSHIFT);
576
577         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
578         case AR_F_SPAN:
579         case AR_F_RAID0:
580             if ((rdp->disks[buf1->drive].flags &
581                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
582                 !AD_SOFTC(rdp->disks[buf1->drive])->dev) {
583                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
584                 ar_config_changed(rdp, 1);
585                 kfree(buf1, M_AR);
586                 bp->b_flags |= B_ERROR;
587                 bp->b_error = EIO;
588                 biodone(bio);
589                 return(0);
590             }
591             dev_dstrategy(AD_SOFTC(rdp->disks[buf1->drive])->dev,
592                           &buf1->bp.b_bio1);
593             break;
594
595         case AR_F_RAID1:
596         case AR_F_RAID0 | AR_F_RAID1:
597             if ((rdp->flags & AR_F_REBUILDING) && bp->b_cmd != BUF_CMD_READ) {
598                 if ((orig_blkno >= rdp->lock_start &&
599                      orig_blkno < rdp->lock_end) ||
600                     ((orig_blkno + chunk) > rdp->lock_start &&
601                      (orig_blkno + chunk) <= rdp->lock_end)) {
602                     tsleep(rdp, 0, "arwait", 0);
603                 }
604             }
605             if ((rdp->disks[buf1->drive].flags &
606                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
607                 !AD_SOFTC(rdp->disks[buf1->drive])->dev) {
608                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
609                 change = 1;
610             }
611             if ((rdp->disks[buf1->drive + rdp->width].flags &
612                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
613                 !AD_SOFTC(rdp->disks[buf1->drive + rdp->width])->dev) {
614                 rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE;
615                 change = 1;
616             }
617             if (change)
618                 ar_config_changed(rdp, 1);
619                 
620             if (!(rdp->flags & AR_F_READY)) {
621                 kfree(buf1, M_AR);
622                 bp->b_flags |= B_ERROR;
623                 bp->b_error = EIO;
624                 biodone(bio);
625                 return(0);
626             }
627             if (bp->b_cmd == BUF_CMD_READ) {
628                 if ((buf1_blkno <
629                      (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) ||
630                      buf1_blkno >
631                      (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY) ||
632                      !(rdp->disks[buf1->drive].flags & AR_DF_ONLINE)) &&
633                      (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE))
634                         buf1->drive = buf1->drive + rdp->width;
635             } else {
636                 if ((rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE) ||
637                     ((rdp->flags & AR_F_REBUILDING) &&
638                      (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_SPARE) &&
639                      buf1_blkno < rdp->lock_start)) {
640                     if ((rdp->disks[buf1->drive].flags & AR_DF_ONLINE) ||
641                         ((rdp->flags & AR_F_REBUILDING) &&
642                          (rdp->disks[buf1->drive].flags & AR_DF_SPARE) &&
643                          buf1_blkno < rdp->lock_start)) {
644                         buf2 = kmalloc(sizeof(struct ar_buf), M_AR, M_INTWAIT);
645                         bcopy(buf1, buf2, sizeof(struct ar_buf));
646                         BUF_LOCKINIT(&buf2->bp);
647                         BUF_LOCK(&buf2->bp, LK_EXCLUSIVE);
648                         initbufbio(&buf2->bp);
649                         buf2->bp.b_bio1.bio_offset = buf1->bp.b_bio1.bio_offset;
650                         buf1->mirror = buf2;
651                         buf2->mirror = buf1;
652                         buf2->drive = buf1->drive + rdp->width;
653                         dev_dstrategy(AD_SOFTC(rdp->disks[buf2->drive])->dev,
654                                       &buf2->bp.b_bio1);
655                         rdp->disks[buf2->drive].last_lba = buf1_blkno + chunk;
656                     }
657                     else
658                         buf1->drive = buf1->drive + rdp->width;
659                 }
660             }
661             dev_dstrategy(AD_SOFTC(rdp->disks[buf1->drive])->dev,
662                           &buf1->bp.b_bio1);
663             rdp->disks[buf1->drive].last_lba = buf1_blkno + chunk;
664             break;
665
666         default:
667             kprintf("ar%d: unknown array type in arstrategy\n", rdp->lun);
668         }
669     }
670     return(0);
671 }
672
673 static void
674 ar_done(struct bio *bio)
675 {
676     struct ar_softc *rdp = (struct ar_softc *)bio->bio_caller_info1.ptr;
677     struct ar_buf *buf = (struct ar_buf *)bio->bio_buf;
678
679     get_mplock();
680
681     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
682     case AR_F_SPAN:
683     case AR_F_RAID0:
684         if (buf->bp.b_flags & B_ERROR) {
685             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
686             ar_config_changed(rdp, 1);
687             buf->org->bio_buf->b_flags |= B_ERROR;
688             buf->org->bio_buf->b_error = EIO;
689             biodone(buf->org);
690         }
691         else {
692             buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
693             if (buf->org->bio_buf->b_resid == 0)
694                 biodone(buf->org);
695         }
696         break;
697
698     case AR_F_RAID1:
699     case AR_F_RAID0 | AR_F_RAID1:
700         if (buf->bp.b_flags & B_ERROR) {
701             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
702             ar_config_changed(rdp, 1);
703             if (rdp->flags & AR_F_READY) {
704                 if (buf->bp.b_cmd == BUF_CMD_READ) {
705                     if (buf->drive < rdp->width)
706                         buf->drive = buf->drive + rdp->width;
707                     else
708                         buf->drive = buf->drive - rdp->width;
709                     buf->bp.b_flags = buf->org->bio_buf->b_flags | B_PAGING;
710                     buf->bp.b_error = 0;
711                     dev_dstrategy(AD_SOFTC(rdp->disks[buf->drive])->dev,
712                                   &buf->bp.b_bio1);
713                     rel_mplock();
714                     return;
715                 }
716                 else {
717                     if (buf->flags & AB_F_DONE) {
718                         buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
719                         if (buf->org->bio_buf->b_resid == 0)
720                             biodone(buf->org);
721                     }
722                     else
723                         buf->mirror->flags |= AB_F_DONE;
724                 }
725             }
726             else {
727                 buf->org->bio_buf->b_flags |= B_ERROR;
728                 buf->org->bio_buf->b_error = EIO;
729                 biodone(buf->org);
730             }
731         } 
732         else {
733             if (buf->bp.b_cmd != BUF_CMD_READ) {
734                 if (buf->mirror && !(buf->flags & AB_F_DONE)){
735                     buf->mirror->flags |= AB_F_DONE;
736                     break;
737                 }
738             }
739             buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
740             if (buf->org->bio_buf->b_resid == 0)
741                 biodone(buf->org);
742         }
743         break;
744         
745     default:
746         kprintf("ar%d: unknown array type in ar_done\n", rdp->lun);
747     }
748     kfree(buf, M_AR);
749     rel_mplock();
750 }
751
752 static void
753 ar_config_changed(struct ar_softc *rdp, int writeback)
754 {
755     int disk, flags;
756
757     flags = rdp->flags;
758     rdp->flags |= AR_F_READY;
759     rdp->flags &= ~AR_F_DEGRADED;
760
761     for (disk = 0; disk < rdp->total_disks; disk++)
762         if (!(rdp->disks[disk].flags & AR_DF_PRESENT))
763             rdp->disks[disk].flags &= ~AR_DF_ONLINE;
764
765     for (disk = 0; disk < rdp->total_disks; disk++) {
766         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
767         case AR_F_SPAN:
768         case AR_F_RAID0:
769             if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) {
770                 rdp->flags &= ~AR_F_READY;
771                 kprintf("ar%d: ERROR - array broken\n", rdp->lun);
772             }
773             break;
774
775         case AR_F_RAID1:
776         case AR_F_RAID0 | AR_F_RAID1:
777             if (disk < rdp->width) {
778                 if (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
779                     !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) {
780                     rdp->flags &= ~AR_F_READY;
781                     kprintf("ar%d: ERROR - array broken\n", rdp->lun);
782                 }
783                 else if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
784                           !(rdp->disks
785                             [disk + rdp->width].flags & AR_DF_ONLINE))||
786                          (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
787                           (rdp->disks
788                            [disk + rdp->width].flags & AR_DF_ONLINE))) {
789                     rdp->flags |= AR_F_DEGRADED;
790                     if (!(flags & AR_F_DEGRADED))
791                         kprintf("ar%d: WARNING - mirror lost\n", rdp->lun);
792                 }
793             }
794             break;
795         }
796         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
797             if (rdp->disks[disk].flags & AR_DF_ONLINE)
798                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
799             else
800                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED);
801         }
802     }
803     if (writeback) {
804         if (rdp->flags & AR_F_PROMISE_RAID)
805             ar_promise_write_conf(rdp);
806         if (rdp->flags & AR_F_HIGHPOINT_RAID)
807             ar_highpoint_write_conf(rdp);
808     }
809 }
810
811 static int
812 ar_rebuild(struct ar_softc *rdp)
813 {
814     int disk, count = 0, error = 0;
815     caddr_t buffer;
816
817     if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED))
818         return EEXIST;
819
820     for (disk = 0; disk < rdp->total_disks; disk++) {
821         if (((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
822              (AR_DF_PRESENT | AR_DF_SPARE)) && rdp->disks[disk].device) {
823             if (AD_SOFTC(rdp->disks[disk])->total_secs <
824                 rdp->disks[disk].disk_sectors) {
825                 ata_prtdev(rdp->disks[disk].device,
826                            "disk capacity too small for this RAID config\n");
827 #if 0
828                 rdp->disks[disk].flags &= ~AR_DF_SPARE;
829                 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
830 #endif
831                 continue;
832             }
833             ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE);
834             count++;
835         }
836     }
837     if (!count)
838         return ENODEV;
839
840     /* setup start conditions */
841     crit_enter();
842     rdp->lock_start = 0;
843     rdp->lock_end = rdp->lock_start + 256;
844     rdp->flags |= AR_F_REBUILDING;
845     crit_exit();
846     buffer = kmalloc(256 * DEV_BSIZE, M_AR, M_WAITOK | M_ZERO);
847
848     /* now go copy entire disk(s) */
849     while (rdp->lock_end < (rdp->total_sectors / rdp->width)) {
850         int size = min(256, (rdp->total_sectors / rdp->width) - rdp->lock_end);
851
852         for (disk = 0; disk < rdp->width; disk++) {
853             struct ad_softc *adp;
854
855             if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
856                  (rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) ||
857                 ((rdp->disks[disk].flags & AR_DF_ONLINE) && 
858                  !(rdp->disks[disk + rdp->width].flags & AR_DF_SPARE)) ||
859                 ((rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) &&
860                  !(rdp->disks[disk].flags & AR_DF_SPARE)))
861                 continue;
862
863             if (rdp->disks[disk].flags & AR_DF_ONLINE)
864                 adp = AD_SOFTC(rdp->disks[disk]);
865             else
866                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
867             if ((error = ar_rw(adp, rdp->lock_start,
868                                size * DEV_BSIZE, buffer, AR_READ | AR_WAIT)))
869                 break;
870
871             if (rdp->disks[disk].flags & AR_DF_ONLINE)
872                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
873             else
874                 adp = AD_SOFTC(rdp->disks[disk]);
875             if ((error = ar_rw(adp, rdp->lock_start,
876                                size * DEV_BSIZE, buffer, AR_WRITE | AR_WAIT)))
877                 break;
878         }
879         if (error) {
880             wakeup(rdp);
881             kfree(buffer, M_AR);
882             return error;
883         }
884         crit_enter();
885         rdp->lock_start = rdp->lock_end;
886         rdp->lock_end = rdp->lock_start + size;
887         crit_exit();
888         wakeup(rdp);
889     }
890     kfree(buffer, M_AR);
891     for (disk = 0; disk < rdp->total_disks; disk++) {
892         if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
893             (AR_DF_PRESENT | AR_DF_SPARE)) {
894             rdp->disks[disk].flags &= ~AR_DF_SPARE;
895             rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE);
896         }
897     }
898     crit_enter();
899     rdp->lock_start = 0xffffffff;
900     rdp->lock_end = 0xffffffff;
901     rdp->flags &= ~AR_F_REBUILDING;
902     crit_exit();
903     ar_config_changed(rdp, 1);
904     return 0;
905 }
906
907 static int
908 ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
909 {
910     struct highpoint_raid_conf *info;
911     struct ar_softc *raid = NULL;
912     int array, disk_number = 0, retval = 0;
913
914     info = kmalloc(sizeof(struct highpoint_raid_conf), M_AR, M_INTWAIT|M_ZERO);
915
916     if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
917               (caddr_t)info, AR_READ | AR_WAIT)) {
918         if (bootverbose)
919             kprintf("ar: HighPoint read conf failed\n");
920         goto highpoint_out;
921     }
922
923     /* check if this is a HighPoint RAID struct */
924     if (info->magic != HPT_MAGIC_OK && info->magic != HPT_MAGIC_BAD) {
925         if (bootverbose)
926             kprintf("ar: HighPoint check1 failed\n");
927         goto highpoint_out;
928     }
929
930     /* is this disk defined, or an old leftover/spare ? */
931     if (!info->magic_0) {
932         if (bootverbose)
933             kprintf("ar: HighPoint check2 failed\n");
934         goto highpoint_out;
935     }
936
937     /* now convert HighPoint config info into our generic form */
938     for (array = 0; array < MAX_ARRAYS; array++) {
939         if (!raidp[array]) {
940             raidp[array] = kmalloc(sizeof(struct ar_softc), M_AR,
941                                          M_INTWAIT | M_ZERO);
942         }
943         raid = raidp[array];
944         if (raid->flags & AR_F_PROMISE_RAID)
945             continue;
946
947         switch (info->type) {
948         case HPT_T_RAID0:
949             if ((info->order & (HPT_O_RAID0|HPT_O_OK))==(HPT_O_RAID0|HPT_O_OK))
950                 goto highpoint_raid1;
951             if (info->order & (HPT_O_RAID0 | HPT_O_RAID1))
952                 goto highpoint_raid01;
953             if (raid->magic_0 && raid->magic_0 != info->magic_0)
954                 continue;
955             raid->magic_0 = info->magic_0;
956             raid->flags |= AR_F_RAID0;
957             raid->interleave = 1 << info->stripe_shift;
958             disk_number = info->disk_number;
959             if (!(info->order & HPT_O_OK))
960                 info->magic = 0;        /* mark bad */
961             break;
962
963         case HPT_T_RAID1:
964 highpoint_raid1:
965             if (raid->magic_0 && raid->magic_0 != info->magic_0)
966                 continue;
967             raid->magic_0 = info->magic_0;
968             raid->flags |= AR_F_RAID1;
969             disk_number = (info->disk_number > 0);
970             break;
971
972         case HPT_T_RAID01_RAID0:
973 highpoint_raid01:
974             if (info->order & HPT_O_RAID0) {
975                 if ((raid->magic_0 && raid->magic_0 != info->magic_0) ||
976                     (raid->magic_1 && raid->magic_1 != info->magic_1))
977                     continue;
978                 raid->magic_0 = info->magic_0;
979                 raid->magic_1 = info->magic_1;
980                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
981                 raid->interleave = 1 << info->stripe_shift;
982                 disk_number = info->disk_number;
983             }
984             else {
985                 if (raid->magic_1 && raid->magic_1 != info->magic_1)
986                     continue;
987                 raid->magic_1 = info->magic_1;
988                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
989                 raid->interleave = 1 << info->stripe_shift;
990                 disk_number = info->disk_number + info->array_width;
991                 if (!(info->order & HPT_O_RAID1))
992                     info->magic = 0;    /* mark bad */
993             }
994             break;
995
996         case HPT_T_SPAN:
997             if (raid->magic_0 && raid->magic_0 != info->magic_0)
998                 continue;
999             raid->magic_0 = info->magic_0;
1000             raid->flags |= AR_F_SPAN;
1001             disk_number = info->disk_number;
1002             break;
1003
1004         default:
1005             kprintf("ar%d: HighPoint unknown RAID type 0x%02x\n",
1006                    array, info->type);
1007             goto highpoint_out;
1008         }
1009
1010         raid->flags |= AR_F_HIGHPOINT_RAID;
1011         raid->disks[disk_number].device = adp->device;
1012         raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED);
1013         raid->lun = array;
1014         if (info->magic == HPT_MAGIC_OK) {
1015             raid->disks[disk_number].flags |= AR_DF_ONLINE;
1016             raid->flags |= AR_F_READY;
1017             raid->width = info->array_width;
1018             raid->heads = 255;
1019             raid->sectors = 63;
1020             raid->cylinders = info->total_sectors / (63 * 255);
1021             raid->total_sectors = info->total_sectors;
1022             raid->offset = HPT_LBA + 1;
1023             raid->reserved = HPT_LBA + 1;
1024             raid->lock_start = raid->lock_end = info->rebuild_lba;
1025             raid->disks[disk_number].disk_sectors =
1026                 info->total_sectors / info->array_width;
1027         }
1028         else
1029             raid->disks[disk_number].flags &= ~ AR_DF_ONLINE;
1030
1031         if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width))
1032             raid->total_disks = raid->width;
1033         if (disk_number >= raid->total_disks)
1034             raid->total_disks = disk_number + 1;
1035         retval = 1;
1036         break;
1037     }
1038 highpoint_out:
1039     kfree(info, M_AR);
1040     return retval;
1041 }
1042
1043 static int
1044 ar_highpoint_write_conf(struct ar_softc *rdp)
1045 {
1046     struct highpoint_raid_conf *config;
1047     struct timeval timestamp;
1048     int disk;
1049
1050     microtime(&timestamp);
1051     rdp->magic_0 = timestamp.tv_sec + 2;
1052     rdp->magic_1 = timestamp.tv_sec;
1053    
1054     for (disk = 0; disk < rdp->total_disks; disk++) {
1055         config = kmalloc(sizeof(struct highpoint_raid_conf),
1056                      M_AR, M_INTWAIT | M_ZERO);
1057         if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
1058             (AR_DF_PRESENT | AR_DF_ONLINE))
1059             config->magic = HPT_MAGIC_OK;
1060         if (rdp->disks[disk].flags & AR_DF_ASSIGNED) {
1061             config->magic_0 = rdp->magic_0;
1062             strcpy(config->name_1, "FreeBSD");
1063         }
1064         config->disk_number = disk;
1065
1066         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1067         case AR_F_RAID0:
1068             config->type = HPT_T_RAID0;
1069             strcpy(config->name_2, "RAID 0");
1070             if (rdp->disks[disk].flags & AR_DF_ONLINE)
1071                 config->order = HPT_O_OK;
1072             break;
1073
1074         case AR_F_RAID1:
1075             config->type = HPT_T_RAID0; /* bogus but old HPT BIOS need it */
1076             strcpy(config->name_2, "RAID 1");
1077             config->disk_number = (disk < rdp->width) ? disk : disk + 5;
1078             config->order = HPT_O_RAID0 | HPT_O_OK;
1079             break;
1080
1081         case AR_F_RAID0 | AR_F_RAID1:
1082             config->type = HPT_T_RAID01_RAID0;
1083             strcpy(config->name_2, "RAID 0+1");
1084             if (rdp->disks[disk].flags & AR_DF_ONLINE) {
1085                 if (disk < rdp->width) {
1086                     config->order = (HPT_O_RAID0 | HPT_O_RAID1);
1087                     config->magic_0 = rdp->magic_0 - 1;
1088                 }
1089                 else {
1090                     config->order = HPT_O_RAID1;
1091                     config->disk_number -= rdp->width;
1092                 }
1093             }
1094             else
1095                 config->magic_0 = rdp->magic_0 - 1;
1096             config->magic_1 = rdp->magic_1;
1097             break;
1098
1099         case AR_F_SPAN:
1100             config->type = HPT_T_SPAN;
1101             strcpy(config->name_2, "SPAN");
1102             break;
1103         }
1104
1105         config->array_width = rdp->width;
1106         config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0;
1107         config->total_sectors = rdp->total_sectors;
1108         config->rebuild_lba = rdp->lock_start;
1109
1110         if ((rdp->disks[disk].device && rdp->disks[disk].device->driver) &&
1111             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1112
1113             if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA,
1114                       sizeof(struct highpoint_raid_conf),
1115                       (caddr_t)config, AR_WRITE)) {
1116                 kprintf("ar%d: Highpoint write conf failed\n", rdp->lun);
1117                 return -1;
1118             }
1119         }
1120     }
1121     return 0;
1122 }
1123
1124 static int
1125 ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
1126 {
1127     struct promise_raid_conf *info;
1128     struct ar_softc *raid;
1129     u_int32_t magic, cksum, *ckptr;
1130     int array, count, disk, disksum = 0, retval = 0; 
1131
1132     info = kmalloc(sizeof(struct promise_raid_conf), M_AR, M_INTWAIT | M_ZERO);
1133
1134     if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
1135               (caddr_t)info, AR_READ | AR_WAIT)) {
1136         if (bootverbose)
1137             kprintf("ar: %s read conf failed\n", local ? "FreeBSD" : "Promise");
1138         goto promise_out;
1139     }
1140
1141     /* check if this is a Promise RAID struct (or our local one) */
1142     if (local) {
1143         if (strncmp(info->promise_id, ATA_MAGIC, sizeof(ATA_MAGIC))) {
1144             if (bootverbose)
1145                 kprintf("ar: FreeBSD check1 failed\n");
1146             goto promise_out;
1147         }
1148     }
1149     else {
1150         if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) {
1151             if (bootverbose)
1152                 kprintf("ar: Promise check1 failed\n");
1153             goto promise_out;
1154         }
1155     }
1156
1157     /* check if the checksum is OK */
1158     for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++)
1159         cksum += *ckptr++;
1160     if (cksum != *ckptr) {  
1161         if (bootverbose)
1162             kprintf("ar: %s check2 failed\n", local ? "FreeBSD" : "Promise");        
1163         goto promise_out;
1164     }
1165
1166     /* now convert Promise config info into our generic form */
1167     if (info->raid.integrity != PR_I_VALID) {
1168         if (bootverbose)
1169             kprintf("ar: %s check3 failed\n", local ? "FreeBSD" : "Promise");        
1170         goto promise_out;
1171     }
1172
1173     for (array = 0; array < MAX_ARRAYS; array++) {
1174         if (!raidp[array]) {
1175             raidp[array] = kmalloc(sizeof(struct ar_softc), M_AR,
1176                                         M_INTWAIT | M_ZERO);
1177         }
1178         raid = raidp[array];
1179         if (raid->flags & AR_F_HIGHPOINT_RAID)
1180             continue;
1181
1182         magic = (adp->device->channel->chiptype >> 16) |
1183                 (info->raid.array_number << 16);
1184
1185         if ((raid->flags & AR_F_PROMISE_RAID) && magic != raid->magic_0)
1186             continue;
1187
1188         /* update our knowledge about the array config based on generation */
1189         if (!info->raid.generation || info->raid.generation > raid->generation){
1190             raid->generation = info->raid.generation;
1191             raid->flags = AR_F_PROMISE_RAID;
1192             if (local)
1193                 raid->flags |= AR_F_FREEBSD_RAID;
1194             raid->magic_0 = magic;
1195             raid->lun = array;
1196             if ((info->raid.status &
1197                  (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) ==
1198                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) {
1199                 raid->flags |= AR_F_READY;
1200                 if (info->raid.status & PR_S_DEGRADED)
1201                     raid->flags |= AR_F_DEGRADED;
1202             }
1203             else
1204                 raid->flags &= ~AR_F_READY;
1205
1206             switch (info->raid.type) {
1207             case PR_T_RAID0:
1208                 raid->flags |= AR_F_RAID0;
1209                 break;
1210
1211             case PR_T_RAID1:
1212                 raid->flags |= AR_F_RAID1;
1213                 if (info->raid.array_width > 1)
1214                     raid->flags |= AR_F_RAID0;
1215                 break;
1216
1217             case PR_T_SPAN:
1218                 raid->flags |= AR_F_SPAN;
1219                 break;
1220
1221             default:
1222                 kprintf("ar%d: %s unknown RAID type 0x%02x\n",
1223                        array, local ? "FreeBSD" : "Promise", info->raid.type);
1224                 goto promise_out;
1225             }
1226             raid->interleave = 1 << info->raid.stripe_shift;
1227             raid->width = info->raid.array_width;
1228             raid->total_disks = info->raid.total_disks;
1229             raid->heads = info->raid.heads + 1;
1230             raid->sectors = info->raid.sectors;
1231             raid->cylinders = info->raid.cylinders + 1;
1232             raid->total_sectors = info->raid.total_sectors;
1233             raid->offset = 0;
1234             raid->reserved = 63;
1235             raid->lock_start = raid->lock_end = info->raid.rebuild_lba;
1236
1237             /* convert disk flags to our internal types */
1238             for (disk = 0; disk < info->raid.total_disks; disk++) {
1239                 raid->disks[disk].flags = 0;
1240                 disksum += info->raid.disk[disk].flags;
1241                 if (info->raid.disk[disk].flags & PR_F_ONLINE)
1242                     raid->disks[disk].flags |= AR_DF_ONLINE;
1243                 if (info->raid.disk[disk].flags & PR_F_ASSIGNED)
1244                     raid->disks[disk].flags |= AR_DF_ASSIGNED;
1245                 if (info->raid.disk[disk].flags & PR_F_SPARE) {
1246                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
1247                     raid->disks[disk].flags |= AR_DF_SPARE;
1248                 }
1249                 if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN))
1250                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
1251             }
1252             if (!disksum) {
1253                 kfree(raidp[array], M_AR);
1254                 raidp[array] = NULL;
1255                 goto promise_out;
1256             }
1257         }
1258         if (raid->disks[info->raid.disk_number].flags && adp->device) {
1259             raid->disks[info->raid.disk_number].device = adp->device;
1260             raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT;
1261             raid->disks[info->raid.disk_number].disk_sectors =
1262                 info->raid.total_sectors / info->raid.array_width;
1263                 /*info->raid.disk_sectors;*/
1264             retval = 1;
1265         }
1266         break;
1267     }
1268 promise_out:
1269     kfree(info, M_AR);
1270     return retval;
1271 }
1272
1273 static int
1274 ar_promise_write_conf(struct ar_softc *rdp)
1275 {
1276     struct promise_raid_conf *config;
1277     struct timeval timestamp;
1278     u_int32_t *ckptr;
1279     int count, disk, drive;
1280     int local = rdp->flags & AR_F_FREEBSD_RAID;
1281
1282     rdp->generation++;
1283     microtime(&timestamp);
1284
1285     for (disk = 0; disk < rdp->total_disks; disk++) {
1286         config = kmalloc(sizeof(struct promise_raid_conf), M_AR, M_INTWAIT);
1287         for (count = 0; count < sizeof(struct promise_raid_conf); count++)
1288             *(((u_int8_t *)config) + count) = 255 - (count % 256);
1289
1290         if (local)
1291             bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC));
1292         else
1293             bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC));
1294         config->dummy_0 = 0x00020000;
1295         config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec;
1296         config->magic_1 = timestamp.tv_sec >> 16;
1297         config->magic_2 = timestamp.tv_sec;
1298         config->raid.integrity = PR_I_VALID;
1299
1300         config->raid.disk_number = disk;
1301         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
1302             config->raid.channel = rdp->disks[disk].device->channel->unit;
1303             config->raid.device = (rdp->disks[disk].device->unit != 0);
1304             if (AD_SOFTC(rdp->disks[disk])->dev)
1305                 config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk]));
1306             /*config->raid.disk_offset*/
1307         }
1308         config->raid.magic_0 = config->magic_0;
1309         config->raid.rebuild_lba = rdp->lock_start;
1310         config->raid.generation = rdp->generation;
1311
1312         if (rdp->flags & AR_F_READY) {
1313             config->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE);
1314             config->raid.status = 
1315                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY);
1316             if (rdp->flags & AR_F_DEGRADED)
1317                 config->raid.status |= PR_S_DEGRADED;
1318             else
1319                 config->raid.status |= PR_S_FUNCTIONAL;
1320         }
1321         else {
1322             config->raid.status = 0;
1323             config->raid.flags = PR_F_DOWN;
1324         }
1325
1326         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1327         case AR_F_RAID0:
1328             config->raid.type = PR_T_RAID0;
1329             break;
1330         case AR_F_RAID1:
1331             config->raid.type = PR_T_RAID1;
1332             break;
1333         case AR_F_RAID0 | AR_F_RAID1:
1334             config->raid.type = PR_T_RAID1;
1335             break;
1336         case AR_F_SPAN:
1337             config->raid.type = PR_T_SPAN;
1338             break;
1339         }
1340
1341         config->raid.total_disks = rdp->total_disks;
1342         config->raid.stripe_shift = ffs(rdp->interleave) - 1;
1343         config->raid.array_width = rdp->width;
1344         config->raid.array_number = rdp->lun;
1345         config->raid.total_sectors = rdp->total_sectors;
1346         config->raid.cylinders = rdp->cylinders - 1;
1347         config->raid.heads = rdp->heads - 1;
1348         config->raid.sectors = rdp->sectors;
1349         config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1;
1350
1351         bzero(&config->raid.disk, 8 * 12);
1352         for (drive = 0; drive < rdp->total_disks; drive++) {
1353             config->raid.disk[drive].flags = 0;
1354             if (rdp->disks[drive].flags & AR_DF_PRESENT)
1355                 config->raid.disk[drive].flags |= PR_F_VALID;
1356             if (rdp->disks[drive].flags & AR_DF_ASSIGNED)
1357                 config->raid.disk[drive].flags |= PR_F_ASSIGNED;
1358             if (rdp->disks[drive].flags & AR_DF_ONLINE)
1359                 config->raid.disk[drive].flags |= PR_F_ONLINE;
1360             else
1361                 if (rdp->disks[drive].flags & AR_DF_PRESENT)
1362                     config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN);
1363             if (rdp->disks[drive].flags & AR_DF_SPARE)
1364                 config->raid.disk[drive].flags |= PR_F_SPARE;
1365             config->raid.disk[drive].dummy_0 = 0x0;
1366             if (rdp->disks[drive].device) {
1367                 config->raid.disk[drive].channel =
1368                     rdp->disks[drive].device->channel->unit;
1369                 config->raid.disk[drive].device =
1370                     (rdp->disks[drive].device->unit != 0);
1371             }
1372             config->raid.disk[drive].magic_0 =
1373                 PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec;
1374         }
1375
1376         config->checksum = 0;
1377         for (ckptr = (int32_t *)config, count = 0; count < 511; count++)
1378             config->checksum += *ckptr++;
1379         if (rdp->disks[disk].device && rdp->disks[disk].device->driver &&
1380             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1381             if (ar_rw(AD_SOFTC(rdp->disks[disk]),
1382                       PR_LBA(AD_SOFTC(rdp->disks[disk])),
1383                       sizeof(struct promise_raid_conf),
1384                       (caddr_t)config, AR_WRITE)) {
1385                 kprintf("ar%d: %s write conf failed\n",
1386                        rdp->lun, local ? "FreeBSD" : "Promise");
1387                 return -1;
1388             }
1389         }
1390     }
1391     return 0;
1392 }
1393
1394 static void
1395 ar_rw_done(struct bio *bio)
1396 {
1397     struct buf *bp = bio->bio_buf;
1398
1399     kfree(bp->b_data, M_AR);
1400     kfree(bp, M_AR);
1401 }
1402
1403 static int
1404 ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags)
1405 {
1406     struct buf *bp;
1407     int retry = 0, error = 0;
1408
1409     bp = kmalloc(sizeof(struct buf), M_AR, M_INTWAIT|M_ZERO);
1410     BUF_LOCKINIT(bp);
1411     BUF_LOCK(bp, LK_EXCLUSIVE);
1412     initbufbio(bp);
1413     bp->b_data = data;
1414     bp->b_bio1.bio_offset = (off_t)lba << DEV_BSHIFT;
1415     bp->b_bcount = count;
1416     if (flags & AR_WAIT) {
1417         bp->b_bio1.bio_flags |= BIO_SYNC;
1418         bp->b_bio1.bio_done = biodone_sync;
1419     } else {
1420         bp->b_bio1.bio_done = ar_rw_done;
1421     }
1422     if (flags & AR_READ)
1423         bp->b_cmd = BUF_CMD_READ;
1424     if (flags & AR_WRITE)
1425         bp->b_cmd = BUF_CMD_WRITE;
1426     KKASSERT(bp->b_cmd != BUF_CMD_DONE);
1427
1428     dev_dstrategy(adp->dev, &bp->b_bio1);
1429
1430     if (flags & AR_WAIT) {
1431         while (retry++ < (15*hz/10))
1432             error = biowait_timeout(&bp->b_bio1, "arrw", 10);
1433         if (!error && (bp->b_flags & B_ERROR))
1434             error = bp->b_error;
1435         if (error == EWOULDBLOCK)
1436             bp->b_bio1.bio_done = ar_rw_done;
1437         else
1438             kfree(bp, M_AR);
1439     }
1440     return error;
1441 }
1442
1443 static struct ata_device *
1444 ar_locate_disk(int diskno)
1445 {
1446     struct ata_channel *ch;
1447     int ctlr;
1448
1449     for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
1450         if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
1451             continue;
1452         if (ch->devices & ATA_ATA_MASTER)
1453             if (ch->device[MASTER].driver &&
1454                 ((struct ad_softc *)(ch->device[MASTER].driver))->lun == diskno)
1455                 return &ch->device[MASTER];
1456         if (ch->devices & ATA_ATA_SLAVE)
1457             if (ch->device[SLAVE].driver &&
1458                 ((struct ad_softc *)(ch->device[SLAVE].driver))->lun == diskno)
1459                 return &ch->device[SLAVE];
1460     }
1461     return NULL;
1462 }