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