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