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