The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ata/ata-raid.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000 - 2004 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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   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/proc.h>
   38 #include <sys/malloc.h>
   39 #include <sys/bio.h>
   40 #include <sys/bus.h>
   41 #include <sys/conf.h>
   42 #include <sys/disk.h>
   43 #include <sys/cons.h>
   44 #include <sys/unistd.h>
   45 #include <sys/kthread.h>
   46 #include <sys/sema.h>
   47 #include <sys/taskqueue.h>
   48 #include <vm/uma.h>
   49 #include <machine/bus.h>
   50 #include <sys/rman.h>
   51 #include <geom/geom_disk.h>
   52 #include <dev/pci/pcivar.h>
   53 #include <dev/pci/pcireg.h>
   54 #include <dev/ata/ata-all.h>
   55 #include <dev/ata/ata-pci.h>
   56 #include <dev/ata/ata-disk.h>
   57 #include <dev/ata/ata-raid.h>
   58 
   59 /* device structures */
   60 static disk_strategy_t  arstrategy;
   61 static dumper_t ardump;
   62 
   63 /* prototypes */
   64 static void ar_attach_raid(struct ar_softc *, int);
   65 static void ar_done(struct bio *);
   66 static void ar_config_changed(struct ar_softc *, int);
   67 static void ar_rebuild(void *);
   68 static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **);
   69 static int ar_highpoint_write_conf(struct ar_softc *);
   70 static int ar_lsi_read_conf(struct ad_softc *, struct ar_softc **);
   71 static int ar_lsi_write_conf(struct ar_softc *);
   72 static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int);
   73 static int ar_promise_write_conf(struct ar_softc *);
   74 static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int);
   75 static struct ata_device *ar_locate_disk(int);
   76 static void ar_print_conf(struct ar_softc *);
   77 
   78 /* internal vars */
   79 static struct ar_softc **ar_table = NULL;
   80 static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver");
   81 
   82 #define AR_REBUILD_SIZE 128
   83 
   84 int
   85 ata_raiddisk_attach(struct ad_softc *adp)
   86 {
   87     struct ar_softc *rdp;
   88     int array, disk;
   89 
   90     if (ar_table) {
   91         for (array = 0; array < MAX_ARRAYS; array++) {
   92             if (!(rdp = ar_table[array]) || !rdp->flags)
   93                 continue;
   94    
   95             for (disk = 0; disk < rdp->total_disks; disk++) {
   96                 if ((rdp->disks[disk].flags & AR_DF_ASSIGNED) &&
   97                     rdp->disks[disk].device == adp->device) {
   98                     ata_prtdev(rdp->disks[disk].device,
   99                                "inserted into ar%d disk%d as spare\n",
  100                                array, disk);
  101                     rdp->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE);
  102                     AD_SOFTC(rdp->disks[disk])->flags |= AD_F_RAID_SUBDISK;
  103                     ar_config_changed(rdp, 1);
  104                     return 1;
  105                 }
  106             }
  107         }
  108     }
  109 
  110     if (!ar_table)
  111         ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
  112                           M_AR, M_NOWAIT | M_ZERO);
  113     if (!ar_table) {
  114         ata_prtdev(adp->device, "no memory for ATA raid array\n");
  115         return 0;
  116     }
  117 
  118     switch(pci_get_vendor(device_get_parent(adp->device->channel->dev))) {
  119     case ATA_PROMISE_ID:
  120         /* test RAID bit in PCI reg XXX */
  121         return (ar_promise_read_conf(adp, ar_table, 0));
  122 
  123     case ATA_HIGHPOINT_ID:
  124         return (ar_highpoint_read_conf(adp, ar_table));
  125 
  126     case ATA_SILICON_IMAGE_ID:
  127         return (ar_lsi_read_conf(adp, ar_table));
  128 
  129     default:
  130         return (ar_promise_read_conf(adp, ar_table, 1));
  131     }
  132     return 0;
  133 }
  134 
  135 int
  136 ata_raiddisk_detach(struct ad_softc *adp)
  137 {
  138     struct ar_softc *rdp;
  139     int array, disk;
  140 
  141     if (ar_table) {
  142         for (array = 0; array < MAX_ARRAYS; array++) {
  143             if (!(rdp = ar_table[array]) || !rdp->flags)
  144                 continue; 
  145             for (disk = 0; disk < rdp->total_disks; disk++) {
  146                 if (rdp->disks[disk].device == adp->device) {
  147                     ata_prtdev(rdp->disks[disk].device,
  148                                "deleted from ar%d disk%d\n", array, disk);
  149                     rdp->disks[disk].flags &= ~(AR_DF_PRESENT | AR_DF_ONLINE);
  150                     AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
  151                     rdp->disks[disk].device = NULL;
  152                     ar_config_changed(rdp, 1);
  153                     return 1;
  154                 }
  155             }
  156         }
  157     }
  158     return 0;
  159 }
  160 
  161 void
  162 ata_raid_attach()
  163 {
  164     struct ar_softc *rdp;
  165     int array;
  166 
  167     if (!ar_table)
  168         return;
  169 
  170     for (array = 0; array < MAX_ARRAYS; array++) {
  171         if (!(rdp = ar_table[array]) || !rdp->flags)
  172             continue;
  173         if (bootverbose)
  174             ar_print_conf(rdp);
  175         ar_attach_raid(rdp, 0);
  176     }
  177 }
  178 
  179 static void
  180 ar_attach_raid(struct ar_softc *rdp, int update)
  181 {
  182     int disk;
  183 
  184     ar_config_changed(rdp, update);
  185     rdp->disk = disk_alloc();
  186     rdp->disk->d_strategy = arstrategy;
  187     rdp->disk->d_dump = ardump;
  188     rdp->disk->d_name = "ar";
  189     rdp->disk->d_sectorsize = DEV_BSIZE;
  190     rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE;
  191     rdp->disk->d_fwsectors = rdp->sectors;
  192     rdp->disk->d_fwheads = rdp->heads;
  193     rdp->disk->d_maxsize = 128 * DEV_BSIZE;
  194     rdp->disk->d_drv1 = rdp;
  195     rdp->disk->d_unit = rdp->lun;
  196     rdp->disk->d_flags = DISKFLAG_NEEDSGIANT;
  197     disk_create(rdp->disk, DISK_VERSION);
  198 
  199     printf("ar%d: %lluMB <ATA ", rdp->lun, (unsigned long long)
  200            (rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE)));
  201     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  202     case AR_F_RAID0:
  203         printf("RAID0 "); break;
  204     case AR_F_RAID1:
  205         printf("RAID1 "); break;
  206     case AR_F_SPAN:
  207         printf("SPAN "); break;
  208     case (AR_F_RAID0 | AR_F_RAID1):
  209         printf("RAID0+1 "); break;
  210     default:
  211         printf("unknown 0x%x> ", rdp->flags);
  212         return;
  213     }
  214     printf("array> [%d/%d/%d] status: ",
  215            rdp->cylinders, rdp->heads, rdp->sectors);
  216     switch (rdp->flags & (AR_F_DEGRADED | AR_F_READY)) {
  217     case AR_F_READY:
  218         printf("READY");
  219         break;
  220     case (AR_F_DEGRADED | AR_F_READY):
  221         printf("DEGRADED");
  222         break;
  223     default:
  224         printf("BROKEN");
  225         break;
  226     }
  227     printf(" subdisks:\n");
  228     for (disk = 0; disk < rdp->total_disks; disk++) {
  229         if (rdp->disks[disk].device &&
  230             AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) {
  231             if (rdp->disks[disk].flags & AR_DF_PRESENT) {
  232                 if (rdp->disks[disk].flags & AR_DF_ONLINE)
  233                     printf(" disk%d READY ", disk);
  234                 else if (rdp->disks[disk].flags & AR_DF_SPARE)
  235                     printf(" disk%d SPARE ", disk);
  236                 else
  237                     printf(" disk%d FREE  ", disk);
  238                 printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name,
  239                        device_get_unit(rdp->disks[disk].device->channel->dev),
  240                        (rdp->disks[disk].device->unit == ATA_MASTER) ?
  241                        "master" : "slave");
  242             }
  243             else if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
  244                 printf(" disk%d DOWN\n", disk);
  245             else
  246                 printf(" disk%d INVALID no RAID config on this disk\n", disk);
  247         }
  248         else
  249             printf(" disk%d DOWN no device found for this disk\n", disk);
  250     }
  251 }
  252 
  253 int
  254 ata_raid_addspare(int array, int disk)
  255 {
  256     struct ar_softc *rdp;
  257     struct ata_device *atadev;
  258     int i;
  259 
  260     if (!ar_table || !(rdp = ar_table[array]))
  261         return ENXIO;
  262     if (!(rdp->flags & AR_F_RAID1))
  263         return EPERM;
  264     if (rdp->flags & AR_F_REBUILDING)
  265         return EBUSY;
  266     if (!(rdp->flags & AR_F_DEGRADED) || !(rdp->flags & AR_F_READY))
  267         return ENXIO;
  268 
  269     for (i = 0; i < rdp->total_disks; i++ ) {
  270         if (((rdp->disks[i].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
  271              (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[i].device)
  272             continue;
  273         if ((atadev = ar_locate_disk(disk))) {
  274             if (((struct ad_softc*)(atadev->softc))->flags & AD_F_RAID_SUBDISK)
  275                 return EBUSY;
  276             rdp->disks[i].device = atadev;
  277             rdp->disks[i].flags |= (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_SPARE);
  278             AD_SOFTC(rdp->disks[i])->flags |= AD_F_RAID_SUBDISK;
  279             ata_prtdev(rdp->disks[i].device,
  280                        "inserted into ar%d disk%d as spare\n", array, i);
  281             ar_config_changed(rdp, 1);
  282             return 0;
  283         }
  284     }
  285     return ENXIO;
  286 }
  287 
  288 int
  289 ata_raid_create(struct raid_setup *setup)
  290 {
  291     struct ata_device *atadev;
  292     struct ar_softc *rdp;
  293     int array, disk;
  294     int ctlr = 0, disk_size = 0, total_disks = 0;
  295 
  296     if (!ar_table)
  297         ar_table = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
  298                           M_AR, M_NOWAIT | M_ZERO);
  299     if (!ar_table) {
  300         printf("ar: no memory for ATA raid array\n");
  301         return 0;
  302     }
  303     for (array = 0; array < MAX_ARRAYS; array++) {
  304         if (!ar_table[array])
  305             break;
  306     }
  307     if (array >= MAX_ARRAYS)
  308         return ENOSPC;
  309 
  310     if (!(rdp = (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
  311                                          M_NOWAIT | M_ZERO))) {
  312         printf("ar%d: failed to allocate raid config storage\n", array);
  313         return ENOMEM;
  314     }
  315 
  316     for (disk = 0; disk < setup->total_disks; disk++) {
  317         if ((atadev = ar_locate_disk(setup->disks[disk]))) {
  318             rdp->disks[disk].device = atadev;
  319             if (AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) {
  320                 setup->disks[disk] = -1;
  321                 free(rdp, M_AR);
  322                 return EBUSY;
  323             }
  324 
  325             switch(pci_get_vendor(device_get_parent(
  326                                   rdp->disks[disk].device->channel->dev))) {
  327             case ATA_HIGHPOINT_ID:
  328                 ctlr |= AR_F_HIGHPOINT_RAID;
  329                 rdp->disks[disk].disk_sectors =
  330                     AD_SOFTC(rdp->disks[disk])->total_secs;
  331                 break;
  332 
  333             case ATA_SILICON_IMAGE_ID:        
  334                 ctlr |= AR_F_LSI_RAID;
  335                 rdp->disks[disk].disk_sectors =
  336                     AD_SOFTC(rdp->disks[disk])->total_secs - 4208; /* SOS */
  337                 break;
  338 
  339             default:
  340                 ctlr |= AR_F_FREEBSD_RAID;
  341                 /* FALLTHROUGH */
  342 
  343             case ATA_PROMISE_ID:        
  344                 ctlr |= AR_F_PROMISE_RAID;
  345                 rdp->disks[disk].disk_sectors =
  346                     PR_LBA(AD_SOFTC(rdp->disks[disk]));
  347                 break;
  348             }
  349 
  350             if ((rdp->flags & 
  351                  (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) &&
  352                 (rdp->flags & 
  353                  (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) !=
  354                 (ctlr &
  355                  (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID))) {
  356                 free(rdp, M_AR);
  357                 return EXDEV;
  358             }
  359             else
  360                 rdp->flags |= ctlr;
  361             
  362             if (disk_size)
  363                 disk_size = min(rdp->disks[disk].disk_sectors, disk_size);
  364             else
  365                 disk_size = rdp->disks[disk].disk_sectors;
  366             rdp->disks[disk].flags = 
  367                 (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
  368 
  369             total_disks++;
  370         }
  371         else {
  372             setup->disks[disk] = -1;
  373             free(rdp, M_AR);
  374             return ENXIO;
  375         }
  376     }
  377     if (!total_disks) {
  378         free(rdp, M_AR);
  379         return ENODEV;
  380     }
  381 
  382     switch (setup->type) {
  383     case 1:
  384         rdp->flags |= AR_F_RAID0;
  385         break;
  386     case 2:
  387         rdp->flags |= AR_F_RAID1;
  388         if (total_disks != 2) {
  389             free(rdp, M_AR);
  390             return EPERM;
  391         }
  392         break;
  393     case 3:
  394         rdp->flags |= (AR_F_RAID0 | AR_F_RAID1);
  395         if (total_disks % 2 != 0) {
  396             free(rdp, M_AR);
  397             return EPERM;
  398         }
  399         break;
  400     case 4:
  401         rdp->flags |= AR_F_SPAN;
  402         break;
  403     }
  404 
  405     for (disk = 0; disk < total_disks; disk++)
  406         AD_SOFTC(rdp->disks[disk])->flags |= AD_F_RAID_SUBDISK;
  407 
  408     rdp->lun = array;
  409     if (rdp->flags & AR_F_RAID0) {
  410         int bit = 0;
  411 
  412         while (setup->interleave >>= 1)
  413             bit++;
  414         if (rdp->flags & AR_F_HIGHPOINT_RAID)
  415             rdp->interleave = min(max(32, 1 << bit), 128);
  416         if (rdp->flags & AR_F_LSI_RAID)
  417             rdp->interleave = min(max(2, 1 << bit), 4096);
  418         if (rdp->flags & AR_F_PROMISE_RAID)
  419             rdp->interleave = min(max(2, 1 << bit), 2048);
  420     }
  421     rdp->total_disks = total_disks;
  422     rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1);     
  423     rdp->total_sectors = disk_size * rdp->width;
  424     rdp->heads = 255;
  425     rdp->sectors = 63;
  426     rdp->cylinders = rdp->total_sectors / (255 * 63);
  427     if (rdp->flags & AR_F_PROMISE_RAID) {
  428         rdp->offset = 0;
  429         rdp->reserved = 63;
  430     }
  431     if (rdp->flags & AR_F_HIGHPOINT_RAID) {
  432         rdp->offset = HPT_LBA + 1;
  433         rdp->reserved = HPT_LBA + 1;
  434     }
  435     rdp->lock_start = rdp->lock_end = 0xffffffff;
  436     rdp->flags |= AR_F_READY;
  437 
  438     ar_table[array] = rdp;
  439 #if 0
  440     /* kick off rebuild here */
  441     if (setup->type == 2) {
  442             rdp->disks[1].flags &= ~AR_DF_ONLINE;
  443             rdp->disks[1].flags |= AR_DF_SPARE;
  444     }
  445 #endif
  446     ar_attach_raid(rdp, 1);
  447     ata_raid_rebuild(array);
  448     setup->unit = array;
  449     return 0;
  450 }
  451 
  452 int
  453 ata_raid_delete(int array)
  454 {
  455     struct ar_softc *rdp;
  456     int disk;
  457 
  458     if (!ar_table) {
  459         printf("ar: no memory for ATA raid array\n");
  460         return 0;
  461     }
  462     if (!(rdp = ar_table[array]))
  463         return ENXIO;
  464     
  465     rdp->flags &= ~AR_F_READY;
  466     for (disk = 0; disk < rdp->total_disks; disk++) {
  467         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
  468             AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
  469 /* SOS
  470             ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
  471    XXX */
  472             rdp->disks[disk].flags = 0;
  473         }
  474     }
  475 
  476     if (rdp->flags & AR_F_HIGHPOINT_RAID)
  477         ar_highpoint_write_conf(rdp);
  478     if (rdp->flags & AR_F_LSI_RAID)
  479         ar_lsi_write_conf(rdp);
  480     if (rdp->flags & AR_F_PROMISE_RAID)
  481         ar_promise_write_conf(rdp);
  482 
  483     disk_destroy(rdp->disk);
  484     free(rdp, M_AR);
  485     ar_table[array] = NULL;
  486     return 0;
  487 }
  488 
  489 int
  490 ata_raid_status(int array, struct raid_status *status)
  491 {
  492     struct ar_softc *rdp;
  493     int i;
  494 
  495     if (!ar_table || !(rdp = ar_table[array]))
  496         return ENXIO;
  497 
  498     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  499     case AR_F_RAID0:
  500         status->type = AR_RAID0;
  501         break;
  502     case AR_F_RAID1:
  503         status->type = AR_RAID1;
  504         break;
  505     case AR_F_RAID0 | AR_F_RAID1:
  506         status->type = AR_RAID0 | AR_RAID1;
  507         break;
  508     case AR_F_SPAN:
  509         status->type = AR_SPAN;
  510         break;
  511     }
  512     status->total_disks = rdp->total_disks;
  513     for (i = 0; i < rdp->total_disks; i++ ) {
  514         if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].device)
  515             status->disks[i] = AD_SOFTC(rdp->disks[i])->lun;
  516         else
  517             status->disks[i] = -1;
  518     }
  519     status->interleave = rdp->interleave;
  520     status->status = 0;
  521     if (rdp->flags & AR_F_READY)
  522         status->status |= AR_READY;
  523     if (rdp->flags & AR_F_DEGRADED)
  524         status->status |= AR_DEGRADED;
  525     if (rdp->flags & AR_F_REBUILDING) {
  526         status->status |= AR_REBUILDING;
  527         status->progress = 100*rdp->lock_start/(rdp->total_sectors/rdp->width);
  528     }
  529     return 0;
  530 }
  531 
  532 int
  533 ata_raid_rebuild(int array)
  534 {
  535     struct ar_softc *rdp;
  536 
  537     if (!ar_table || !(rdp = ar_table[array]))
  538         return ENXIO;
  539     if (rdp->flags & AR_F_REBUILDING)
  540         return EBUSY;
  541     return kthread_create(ar_rebuild, rdp, &rdp->pid, RFNOWAIT, 0,
  542                           "rebuilding ar%d", array);
  543 }
  544 
  545 static int
  546 ardump(void *arg, void *virtual, vm_offset_t physical,
  547        off_t offset, size_t length)
  548 {
  549     struct ar_softc *rdp;
  550     struct disk *dp, *ap;
  551     vm_offset_t pdata;
  552     caddr_t vdata;
  553     int blkno, count, chunk, error1, error2, lba, lbs, tmplba;
  554     int drv = 0;
  555 
  556     dp = arg;
  557     rdp = dp->d_drv1;
  558     if (!rdp || !(rdp->flags & AR_F_READY))
  559         return ENXIO;
  560 
  561     if (length == 0) {
  562         for (drv = 0; drv < rdp->total_disks; drv++) {
  563             if (rdp->disks[drv].flags & AR_DF_ONLINE) {
  564                 ap = AD_SOFTC(rdp->disks[drv])->disk;
  565                 (void) ap->d_dump(ap, NULL, 0, 0, 0);
  566             }
  567         }
  568         return 0;
  569     }
  570     
  571     blkno = offset / DEV_BSIZE;
  572     vdata = virtual;
  573     pdata = physical;
  574     
  575     for (count = howmany(length, DEV_BSIZE); count > 0; 
  576          count -= chunk, blkno += chunk, vdata += (chunk * DEV_BSIZE),
  577          pdata += (chunk * DEV_BSIZE)) {
  578 
  579         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  580         case AR_F_SPAN:
  581             lba = blkno;
  582             while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
  583                 lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
  584             chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
  585                         count);
  586             break;
  587         
  588         case AR_F_RAID0:
  589         case AR_F_RAID0 | AR_F_RAID1:
  590             tmplba = blkno / rdp->interleave;
  591             chunk = blkno % rdp->interleave;
  592             if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) *
  593                          (rdp->interleave * rdp->width) ) {
  594                 lbs = (rdp->total_sectors - 
  595                     ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
  596                      (rdp->interleave * rdp->width))) / rdp->width;
  597                 drv = (blkno - 
  598                     ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
  599                      (rdp->interleave * rdp->width))) / lbs;
  600                 lba = ((tmplba / rdp->width) * rdp->interleave) +
  601                       (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
  602                 chunk = min(count, lbs);
  603             }
  604             else {
  605                 drv = tmplba % rdp->width;
  606                 lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
  607                 chunk = min(count, rdp->interleave - chunk);
  608             }
  609             break;
  610             
  611         case AR_F_RAID1:
  612             drv = 0;
  613             lba = blkno;
  614             chunk = count;
  615             break;
  616             
  617         default:
  618             printf("ar%d: unknown array type in ardump\n", rdp->lun);
  619             return EIO;
  620         }
  621 
  622         if (drv > 0)
  623             lba += rdp->offset;
  624 
  625         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  626         case AR_F_SPAN:
  627         case AR_F_RAID0:
  628             if (rdp->disks[drv].flags & AR_DF_ONLINE) {
  629                 ap = AD_SOFTC(rdp->disks[drv])->disk;
  630                 error1 = ap->d_dump(ap, vdata, pdata,
  631                                     (off_t) lba * DEV_BSIZE,
  632                                     chunk * DEV_BSIZE);
  633             } else
  634                 error1 = EIO;
  635             if (error1)
  636                 return error1;
  637             break;
  638 
  639         case AR_F_RAID1:
  640         case AR_F_RAID0 | AR_F_RAID1:
  641             if ((rdp->disks[drv].flags & AR_DF_ONLINE) ||
  642                 ((rdp->flags & AR_F_REBUILDING) && 
  643                  (rdp->disks[drv].flags & AR_DF_SPARE))) {
  644                 ap = AD_SOFTC(rdp->disks[drv])->disk;
  645                 error1 = ap->d_dump(ap, vdata, pdata,
  646                                     (off_t) lba * DEV_BSIZE,
  647                                     chunk * DEV_BSIZE);
  648             } else
  649                 error1 = EIO;
  650             if ((rdp->disks[drv + rdp->width].flags & AR_DF_ONLINE) ||
  651                 ((rdp->flags & AR_F_REBUILDING) &&
  652                  (rdp->disks[drv + rdp->width].flags & AR_DF_SPARE))) {
  653                 ap = AD_SOFTC(rdp->disks[drv + rdp->width])->disk;
  654                 error2 = ap->d_dump(ap, vdata, pdata,
  655                                     (off_t) lba * DEV_BSIZE,
  656                                     chunk * DEV_BSIZE);
  657             } else
  658                 error2 = EIO;
  659             if (error1 && error2)
  660                 return error1;
  661             break;
  662             
  663         default:
  664             printf("ar%d: unknown array type in ardump\n", rdp->lun);
  665             return EIO;
  666         }
  667     }
  668     return 0;
  669 }
  670 
  671 static void
  672 arstrategy(struct bio *bp)
  673 {
  674     struct ar_softc *rdp = bp->bio_disk->d_drv1;
  675     int blkno, count, chunk, lba, lbs, tmplba;
  676     int drv = 0, change = 0;
  677     caddr_t data;
  678 
  679     if (!(rdp->flags & AR_F_READY)) {
  680         bp->bio_flags |= BIO_ERROR;
  681         bp->bio_error = EIO;
  682         biodone(bp);
  683         return;
  684     }
  685 
  686     bp->bio_resid = bp->bio_bcount;
  687     blkno = bp->bio_pblkno;
  688     data = bp->bio_data;
  689     for (count = howmany(bp->bio_bcount, DEV_BSIZE); count > 0; 
  690          count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) {
  691         struct ar_buf *buf1, *buf2;
  692 
  693         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  694         case AR_F_SPAN:
  695             lba = blkno;
  696             while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
  697                 lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
  698             chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
  699                         count);
  700             break;
  701         
  702         case AR_F_RAID0:
  703         case AR_F_RAID0 | AR_F_RAID1:
  704             tmplba = blkno / rdp->interleave;
  705             chunk = blkno % rdp->interleave;
  706             if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) *
  707                          (rdp->interleave * rdp->width) ) {
  708                 lbs = (rdp->total_sectors - 
  709                     ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
  710                      (rdp->interleave * rdp->width))) / rdp->width;
  711                 drv = (blkno - 
  712                     ((rdp->total_sectors / (rdp->interleave * rdp->width)) *
  713                      (rdp->interleave * rdp->width))) / lbs;
  714                 lba = ((tmplba / rdp->width) * rdp->interleave) +
  715                       (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
  716                 chunk = min(count, lbs);
  717             }
  718             else {
  719                 drv = tmplba % rdp->width;
  720                 lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
  721                 chunk = min(count, rdp->interleave - chunk);
  722             }
  723             break;
  724 
  725         case AR_F_RAID1:
  726             drv = 0;
  727             lba = blkno;
  728             chunk = count;
  729             break;
  730 
  731         default:
  732             printf("ar%d: unknown array type in arstrategy\n", rdp->lun);
  733             bp->bio_flags |= BIO_ERROR;
  734             bp->bio_error = EIO;
  735             biodone(bp);
  736             return;
  737         }
  738 
  739         buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO); /* XXX */
  740         buf1->bp.bio_pblkno = lba;
  741         if ((buf1->drive = drv) > 0)
  742             buf1->bp.bio_pblkno += rdp->offset;
  743         buf1->bp.bio_driver1 = (void *)rdp;
  744         buf1->bp.bio_bcount = chunk * DEV_BSIZE;
  745         buf1->bp.bio_data = data;
  746         buf1->bp.bio_cmd = bp->bio_cmd;
  747         buf1->bp.bio_flags = bp->bio_flags;
  748         buf1->bp.bio_done = ar_done;
  749         buf1->org = bp;
  750 
  751         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  752         case AR_F_SPAN:
  753         case AR_F_RAID0:
  754             if ((rdp->disks[buf1->drive].flags &
  755                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
  756                 !rdp->disks[buf1->drive].device->softc) {
  757                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
  758                 ar_config_changed(rdp, 1);
  759                 free(buf1, M_AR);
  760                 bp->bio_flags |= BIO_ERROR;
  761                 bp->bio_error = EIO;
  762                 biodone(bp);
  763                 return;
  764             }
  765             buf1->bp.bio_disk = AD_SOFTC(rdp->disks[buf1->drive])->disk;
  766             AR_STRATEGY((struct bio *)buf1);
  767             break;
  768 
  769         case AR_F_RAID1:
  770         case AR_F_RAID0 | AR_F_RAID1:
  771             if (rdp->flags & AR_F_REBUILDING && bp->bio_cmd == BIO_WRITE) {
  772                 if ((bp->bio_pblkno >= rdp->lock_start &&
  773                      bp->bio_pblkno < rdp->lock_end) ||
  774                     ((bp->bio_pblkno + chunk) > rdp->lock_start &&
  775                      (bp->bio_pblkno + chunk) <= rdp->lock_end)) {
  776                     tsleep(rdp, PRIBIO, "arwait", 0);
  777                 }
  778             }
  779             if ((rdp->disks[buf1->drive].flags &
  780                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
  781                 !rdp->disks[buf1->drive].device->softc) {
  782                 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
  783                 change = 1;
  784             }
  785             if ((rdp->disks[buf1->drive + rdp->width].flags &
  786                  (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
  787                 !rdp->disks[buf1->drive + rdp->width].device->softc) {
  788                 rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE;
  789                 change = 1;
  790             }
  791             if (change)
  792                 ar_config_changed(rdp, 1);
  793                 
  794             if (!(rdp->flags & AR_F_READY)) {
  795                 free(buf1, M_AR);
  796                 bp->bio_flags |= BIO_ERROR;
  797                 bp->bio_error = EIO;
  798                 biodone(bp);
  799                 return;
  800             }
  801             if (bp->bio_cmd == BIO_READ) {
  802                 int src_online =
  803                     (rdp->disks[buf1->drive].flags & AR_DF_ONLINE);
  804                 int mir_online =
  805                     (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE);
  806 
  807                 /* if mirror gone or close to last access on source */
  808                 if (!mir_online || 
  809                     ((src_online) &&
  810                      buf1->bp.bio_pblkno >=
  811                      (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) &&
  812                      buf1->bp.bio_pblkno <=
  813                      (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY))) {
  814                     rdp->flags &= ~AR_F_TOGGLE;
  815                 } 
  816                 /* if source gone or close to last access on mirror */
  817                 else if (!src_online ||
  818                          ((mir_online) &&
  819                           buf1->bp.bio_pblkno >=
  820                           (rdp->disks[buf1->drive + rdp->width].last_lba -
  821                            AR_PROXIMITY) &&
  822                           buf1->bp.bio_pblkno <=
  823                           (rdp->disks[buf1->drive + rdp->width].last_lba +
  824                            AR_PROXIMITY))) {
  825                     buf1->drive = buf1->drive + rdp->width;
  826                     rdp->flags |= AR_F_TOGGLE;
  827                 }
  828                 /* not close to any previous access, toggle */
  829                 else {
  830                     if (rdp->flags & AR_F_TOGGLE)
  831                         rdp->flags &= ~AR_F_TOGGLE;
  832                     else {
  833                         buf1->drive = buf1->drive + rdp->width;
  834                         rdp->flags |= AR_F_TOGGLE;
  835                     }
  836                 }
  837             }
  838             if (bp->bio_cmd == BIO_WRITE) {
  839                 if ((rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE) ||
  840                     ((rdp->flags & AR_F_REBUILDING) &&
  841                      (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_SPARE) &&
  842                      buf1->bp.bio_pblkno < rdp->lock_start)) {
  843                     if ((rdp->disks[buf1->drive].flags & AR_DF_ONLINE) ||
  844                         ((rdp->flags & AR_F_REBUILDING) &&
  845                          (rdp->disks[buf1->drive].flags & AR_DF_SPARE) &&
  846                          buf1->bp.bio_pblkno < rdp->lock_start)) {
  847                         buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); /* XXX */
  848                         bcopy(buf1, buf2, sizeof(struct ar_buf));
  849                         buf1->mirror = buf2;
  850                         buf2->mirror = buf1;
  851                         buf2->drive = buf1->drive + rdp->width;
  852                         buf2->bp.bio_disk =
  853                             AD_SOFTC(rdp->disks[buf2->drive])->disk;
  854                         AR_STRATEGY((struct bio *)buf2);
  855                         rdp->disks[buf2->drive].last_lba =
  856                             buf2->bp.bio_pblkno + chunk;
  857                     }
  858                     else
  859                         buf1->drive = buf1->drive + rdp->width;
  860                 }
  861             }
  862             buf1->bp.bio_disk = AD_SOFTC(rdp->disks[buf1->drive])->disk;
  863             AR_STRATEGY((struct bio *)buf1);
  864             rdp->disks[buf1->drive].last_lba = buf1->bp.bio_pblkno + chunk;
  865             break;
  866 
  867         default:
  868             printf("ar%d: unknown array type in arstrategy\n", rdp->lun);
  869         }
  870     }
  871 }
  872 
  873 static void
  874 ar_done(struct bio *bp)
  875 {
  876     struct ar_softc *rdp = (struct ar_softc *)bp->bio_driver1;
  877     struct ar_buf *buf = (struct ar_buf *)bp;
  878 
  879     switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  880     case AR_F_SPAN:
  881     case AR_F_RAID0:
  882         if (buf->bp.bio_flags & BIO_ERROR) {
  883             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
  884             ar_config_changed(rdp, 1);
  885             buf->org->bio_flags |= BIO_ERROR;
  886             buf->org->bio_error = EIO;
  887             biodone(buf->org);
  888         }
  889         else {
  890             buf->org->bio_resid -= buf->bp.bio_bcount;
  891             if (buf->org->bio_resid == 0)
  892                 biodone(buf->org);
  893         }
  894         break;
  895 
  896     case AR_F_RAID1:
  897     case AR_F_RAID0 | AR_F_RAID1:
  898         if (buf->bp.bio_flags & BIO_ERROR) {
  899             rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
  900             ar_config_changed(rdp, 1);
  901             if (rdp->flags & AR_F_READY) {
  902                 if (buf->bp.bio_cmd == BIO_READ) {
  903                     if (buf->drive < rdp->width)
  904                         buf->drive = buf->drive + rdp->width;
  905                     else
  906                         buf->drive = buf->drive - rdp->width;
  907                     buf->bp.bio_disk = AD_SOFTC(rdp->disks[buf->drive])->disk;
  908                     buf->bp.bio_flags = buf->org->bio_flags;
  909                     buf->bp.bio_error = 0;
  910                     AR_STRATEGY((struct bio *)buf);
  911                     return;
  912                 }
  913                 if (buf->bp.bio_cmd == BIO_WRITE) {
  914                     if (buf->flags & AB_F_DONE) {
  915                         buf->org->bio_resid -= buf->bp.bio_bcount;
  916                         if (buf->org->bio_resid == 0)
  917                             biodone(buf->org);
  918                     }
  919                     else
  920                         buf->mirror->flags |= AB_F_DONE;
  921                 }
  922             }
  923             else {
  924                 buf->org->bio_flags |= BIO_ERROR;
  925                 buf->org->bio_error = EIO;
  926                 biodone(buf->org);
  927             }
  928         } 
  929         else {
  930             if (buf->bp.bio_cmd == BIO_WRITE) {
  931                 if (buf->mirror && !(buf->flags & AB_F_DONE)){
  932                     buf->mirror->flags |= AB_F_DONE;
  933                     break;
  934                 }
  935             }
  936             buf->org->bio_resid -= buf->bp.bio_bcount;
  937             if (buf->org->bio_resid == 0)
  938                 biodone(buf->org);
  939         }
  940         break;
  941         
  942     default:
  943         printf("ar%d: unknown array type in ar_done\n", rdp->lun);
  944     }
  945     free(buf, M_AR);
  946 }
  947 
  948 static void
  949 ar_config_changed(struct ar_softc *rdp, int writeback)
  950 {
  951     int disk, flags;
  952 
  953     flags = rdp->flags;
  954     rdp->flags |= AR_F_READY;
  955     rdp->flags &= ~AR_F_DEGRADED;
  956 
  957     for (disk = 0; disk < rdp->total_disks; disk++)
  958         if (!(rdp->disks[disk].flags & AR_DF_PRESENT))
  959             rdp->disks[disk].flags &= ~AR_DF_ONLINE;
  960 
  961     for (disk = 0; disk < rdp->total_disks; disk++) {
  962         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
  963         case AR_F_SPAN:
  964         case AR_F_RAID0:
  965             if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) {
  966                 rdp->flags &= ~AR_F_READY;
  967                 printf("ar%d: ERROR - array broken\n", rdp->lun);
  968             }
  969             break;
  970 
  971         case AR_F_RAID1:
  972         case AR_F_RAID0 | AR_F_RAID1:
  973             if (disk < rdp->width) {
  974                 if (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
  975                     !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) {
  976                     rdp->flags &= ~AR_F_READY;
  977                     printf("ar%d: ERROR - array broken\n", rdp->lun);
  978                 }
  979                 else if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
  980                           !(rdp->disks
  981                             [disk + rdp->width].flags & AR_DF_ONLINE))||
  982                          (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
  983                           (rdp->disks
  984                            [disk + rdp->width].flags & AR_DF_ONLINE))) {
  985                     rdp->flags |= AR_F_DEGRADED;
  986                     if (!(flags & AR_F_DEGRADED))
  987                         printf("ar%d: WARNING - mirror lost\n", rdp->lun);
  988                 }
  989             }
  990             break;
  991         }
  992         if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
  993 /* SOS
  994             if (rdp->disks[disk].flags & AR_DF_ONLINE)
  995                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
  996             else
  997                 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED);
  998    XXX */
  999         }
 1000     }
 1001     if (writeback) {
 1002         if (rdp->flags & AR_F_HIGHPOINT_RAID)
 1003             ar_highpoint_write_conf(rdp);
 1004         if (rdp->flags & AR_F_LSI_RAID)
 1005             ar_lsi_write_conf(rdp);
 1006         if (rdp->flags & AR_F_PROMISE_RAID)
 1007             ar_promise_write_conf(rdp);
 1008     }
 1009 }
 1010 
 1011 static void
 1012 ar_rebuild(void *arg)
 1013 {
 1014     struct ar_softc *rdp = arg;
 1015     int disk, s, count = 0, error = 0;
 1016     caddr_t buffer;
 1017 
 1018     mtx_lock(&Giant);
 1019     if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED))
 1020         kthread_exit(EEXIST);
 1021 
 1022     for (disk = 0; disk < rdp->total_disks; disk++) {
 1023         if (((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
 1024              (AR_DF_PRESENT | AR_DF_SPARE)) && rdp->disks[disk].device) {
 1025             if (AD_SOFTC(rdp->disks[disk])->total_secs <
 1026                 rdp->disks[disk].disk_sectors) {
 1027                 ata_prtdev(rdp->disks[disk].device,
 1028                            "disk capacity too small for this RAID config\n");
 1029 #if 0
 1030                 rdp->disks[disk].flags &= ~AR_DF_SPARE;
 1031                 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
 1032 #endif
 1033                 continue;
 1034             }
 1035 /* SOS
 1036             ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE);
 1037    XXX */
 1038             count++;
 1039         }
 1040     }
 1041     if (!count)
 1042         kthread_exit(ENODEV);
 1043 
 1044     /* setup start conditions */
 1045     s = splbio();
 1046     rdp->lock_start = 0;
 1047     rdp->lock_end = rdp->lock_start + AR_REBUILD_SIZE;
 1048     rdp->flags |= AR_F_REBUILDING;
 1049     splx(s);
 1050     buffer = malloc(AR_REBUILD_SIZE * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO); /* XXX */
 1051 
 1052     /* now go copy entire disk(s) */
 1053     while (rdp->lock_end < (rdp->total_sectors / rdp->width)) {
 1054         int size = min(AR_REBUILD_SIZE, 
 1055                        (rdp->total_sectors / rdp->width) - rdp->lock_end);
 1056 
 1057         for (disk = 0; disk < rdp->width; disk++) {
 1058             struct ad_softc *adp;
 1059 
 1060             if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
 1061                  (rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) ||
 1062                 ((rdp->disks[disk].flags & AR_DF_ONLINE) && 
 1063                  !(rdp->disks[disk + rdp->width].flags & AR_DF_SPARE)) ||
 1064                 ((rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) &&
 1065                  !(rdp->disks[disk].flags & AR_DF_SPARE)))
 1066                 continue;
 1067 
 1068             if (rdp->disks[disk].flags & AR_DF_ONLINE)
 1069                 adp = AD_SOFTC(rdp->disks[disk]);
 1070             else
 1071                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
 1072             if ((error = ar_rw(adp, rdp->lock_start,
 1073                                size * DEV_BSIZE, buffer, AR_READ | AR_WAIT)))
 1074                 break;
 1075 
 1076             if (rdp->disks[disk].flags & AR_DF_ONLINE)
 1077                 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
 1078             else
 1079                 adp = AD_SOFTC(rdp->disks[disk]);
 1080             if ((error = ar_rw(adp, rdp->lock_start,
 1081                                size * DEV_BSIZE, buffer, AR_WRITE | AR_WAIT)))
 1082                 break;
 1083         }
 1084         if (error) {
 1085             wakeup(rdp);
 1086             free(buffer, M_AR);
 1087             kthread_exit(error);
 1088         }
 1089         s = splbio();
 1090         rdp->lock_start = rdp->lock_end;
 1091         rdp->lock_end = rdp->lock_start + size;
 1092         splx(s);
 1093         wakeup(rdp);
 1094         sprintf(rdp->pid->p_comm, "rebuilding ar%d %lld%%", rdp->lun,
 1095                 (unsigned long long)(100 * rdp->lock_start /
 1096                                      (rdp->total_sectors / rdp->width)));
 1097     }
 1098     free(buffer, M_AR);
 1099     for (disk = 0; disk < rdp->total_disks; disk++) {
 1100         if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
 1101             (AR_DF_PRESENT | AR_DF_SPARE)) {
 1102             rdp->disks[disk].flags &= ~AR_DF_SPARE;
 1103             rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE);
 1104         }
 1105     }
 1106     s = splbio();
 1107     rdp->lock_start = 0xffffffff;
 1108     rdp->lock_end = 0xffffffff;
 1109     rdp->flags &= ~AR_F_REBUILDING;
 1110     splx(s);
 1111     ar_config_changed(rdp, 1);
 1112     kthread_exit(0);
 1113 }
 1114 
 1115 static int
 1116 ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
 1117 {
 1118     struct highpoint_raid_conf *info;
 1119     struct ar_softc *raid = NULL;
 1120     int array, disk_number = 0, retval = 0;
 1121 
 1122     if (!(info = (struct highpoint_raid_conf *)
 1123           malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
 1124         return retval;
 1125 
 1126     if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
 1127               (caddr_t)info, AR_READ | AR_WAIT)) {
 1128         if (bootverbose)
 1129             printf("ar: HighPoint read conf failed\n");
 1130         goto highpoint_out;
 1131     }
 1132 
 1133     /* check if this is a HighPoint RAID struct */
 1134     if (info->magic != HPT_MAGIC_OK && info->magic != HPT_MAGIC_BAD) {
 1135         if (bootverbose)
 1136             printf("ar: HighPoint check1 failed\n");
 1137         goto highpoint_out;
 1138     }
 1139 
 1140     /* is this disk defined, or an old leftover/spare ? */
 1141     if (!info->magic_0) {
 1142         if (bootverbose)
 1143             printf("ar: HighPoint check2 failed\n");
 1144         goto highpoint_out;
 1145     }
 1146 
 1147     /* now convert HighPoint config info into our generic form */
 1148     for (array = 0; array < MAX_ARRAYS; array++) {
 1149         if (!raidp[array]) {
 1150             raidp[array] = 
 1151                 (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
 1152                                          M_NOWAIT | M_ZERO);
 1153             if (!raidp[array]) {
 1154                 printf("ar%d: failed to allocate raid config storage\n", array);
 1155                 goto highpoint_out;
 1156             }
 1157         }
 1158         raid = raidp[array];
 1159         if (raid->flags & (AR_F_PROMISE_RAID | AR_F_LSI_RAID))
 1160             continue;
 1161 
 1162         switch (info->type) {
 1163         case HPT_T_RAID0:
 1164             if ((info->order & (HPT_O_RAID0|HPT_O_OK))==(HPT_O_RAID0|HPT_O_OK))
 1165                 goto highpoint_raid1;
 1166             if (info->order & (HPT_O_RAID0 | HPT_O_RAID1))
 1167                 goto highpoint_raid01;
 1168             if (raid->magic_0 && raid->magic_0 != info->magic_0)
 1169                 continue;
 1170             raid->magic_0 = info->magic_0;
 1171             raid->flags |= AR_F_RAID0;
 1172             raid->interleave = 1 << info->stripe_shift;
 1173             disk_number = info->disk_number;
 1174             if (!(info->order & HPT_O_OK))
 1175                 info->magic = 0;        /* mark bad */
 1176             break;
 1177 
 1178         case HPT_T_RAID1:
 1179 highpoint_raid1:
 1180             if (raid->magic_0 && raid->magic_0 != info->magic_0)
 1181                 continue;
 1182             raid->magic_0 = info->magic_0;
 1183             raid->flags |= AR_F_RAID1;
 1184             disk_number = (info->disk_number > 0);
 1185             break;
 1186 
 1187         case HPT_T_RAID01_RAID0:
 1188 highpoint_raid01:
 1189             if (info->order & HPT_O_RAID0) {
 1190                 if ((raid->magic_0 && raid->magic_0 != info->magic_0) ||
 1191                     (raid->magic_1 && raid->magic_1 != info->magic_1))
 1192                     continue;
 1193                 raid->magic_0 = info->magic_0;
 1194                 raid->magic_1 = info->magic_1;
 1195                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
 1196                 raid->interleave = 1 << info->stripe_shift;
 1197                 disk_number = info->disk_number;
 1198             }
 1199             else {
 1200                 if (raid->magic_1 && raid->magic_1 != info->magic_1)
 1201                     continue;
 1202                 raid->magic_1 = info->magic_1;
 1203                 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
 1204                 raid->interleave = 1 << info->stripe_shift;
 1205                 disk_number = info->disk_number + info->array_width;
 1206                 if (!(info->order & HPT_O_RAID1))
 1207                     info->magic = 0;    /* mark bad */
 1208             }
 1209             break;
 1210 
 1211         case HPT_T_SPAN:
 1212             if (raid->magic_0 && raid->magic_0 != info->magic_0)
 1213                 continue;
 1214             raid->magic_0 = info->magic_0;
 1215             raid->flags |= AR_F_SPAN;
 1216             disk_number = info->disk_number;
 1217             break;
 1218 
 1219         default:
 1220             printf("ar%d: HighPoint unknown RAID type 0x%02x\n",
 1221                    array, info->type);
 1222             free(raidp[array], M_AR);
 1223             raidp[array] = NULL;
 1224             goto highpoint_out;
 1225         }
 1226 
 1227         raid->flags |= AR_F_HIGHPOINT_RAID;
 1228         raid->disks[disk_number].device = adp->device;
 1229         raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED);
 1230         AD_SOFTC(raid->disks[disk_number])->flags |= AD_F_RAID_SUBDISK;
 1231         raid->lun = array;
 1232         if (info->magic == HPT_MAGIC_OK) {
 1233             raid->disks[disk_number].flags |= AR_DF_ONLINE;
 1234             raid->flags |= AR_F_READY;
 1235             raid->width = info->array_width;
 1236             raid->heads = 255;
 1237             raid->sectors = 63;
 1238             raid->cylinders = info->total_sectors / (63 * 255);
 1239             raid->total_sectors = info->total_sectors;
 1240             raid->offset = HPT_LBA + 1;
 1241             raid->reserved = HPT_LBA + 1;
 1242             raid->lock_start = raid->lock_end = info->rebuild_lba;
 1243             raid->disks[disk_number].disk_sectors =
 1244                 info->total_sectors / info->array_width;
 1245         }
 1246         else
 1247             raid->disks[disk_number].flags &= ~ AR_DF_ONLINE;
 1248 
 1249         if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width))
 1250             raid->total_disks = raid->width;
 1251         if (disk_number >= raid->total_disks)
 1252             raid->total_disks = disk_number + 1;
 1253         retval = 1;
 1254         break;
 1255     }
 1256 
 1257 highpoint_out:
 1258     free(info, M_AR);
 1259     return retval;
 1260 }
 1261 
 1262 static int
 1263 ar_highpoint_write_conf(struct ar_softc *rdp)
 1264 {
 1265     struct highpoint_raid_conf *config;
 1266     struct timeval timestamp;
 1267     int disk;
 1268 
 1269     microtime(&timestamp);
 1270     rdp->magic_0 = timestamp.tv_sec + 2;
 1271     rdp->magic_1 = timestamp.tv_sec;
 1272    
 1273     for (disk = 0; disk < rdp->total_disks; disk++) {
 1274         if (!(config = (struct highpoint_raid_conf *)
 1275               malloc(sizeof(struct highpoint_raid_conf),
 1276                      M_AR, M_NOWAIT | M_ZERO))) {
 1277             printf("ar%d: Highpoint write conf failed\n", rdp->lun);
 1278             return -1;
 1279         }
 1280         if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
 1281             (AR_DF_PRESENT | AR_DF_ONLINE))
 1282             config->magic = HPT_MAGIC_OK;
 1283         if (rdp->disks[disk].flags & AR_DF_ASSIGNED) {
 1284             config->magic_0 = rdp->magic_0;
 1285             strcpy(config->name_1, "FreeBSD");
 1286         }
 1287         config->disk_number = disk;
 1288 
 1289         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
 1290         case AR_F_RAID0:
 1291             config->type = HPT_T_RAID0;
 1292             strcpy(config->name_2, "RAID 0");
 1293             if (rdp->disks[disk].flags & AR_DF_ONLINE)
 1294                 config->order = HPT_O_OK;
 1295             break;
 1296 
 1297         case AR_F_RAID1:
 1298             config->type = HPT_T_RAID0;
 1299             strcpy(config->name_2, "RAID 1");
 1300             config->disk_number = (disk < rdp->width) ? disk : disk + 5;
 1301             config->order = HPT_O_RAID0 | HPT_O_OK;
 1302             break;
 1303 
 1304         case AR_F_RAID0 | AR_F_RAID1:
 1305             config->type = HPT_T_RAID01_RAID0;
 1306             strcpy(config->name_2, "RAID 0+1");
 1307             if (rdp->disks[disk].flags & AR_DF_ONLINE) {
 1308                 if (disk < rdp->width) {
 1309                     config->order = (HPT_O_RAID0 | HPT_O_RAID1);
 1310                     config->magic_0 = rdp->magic_0 - 1;
 1311                 }
 1312                 else {
 1313                     config->order = HPT_O_RAID1;
 1314                     config->disk_number -= rdp->width;
 1315                 }
 1316             }
 1317             else
 1318                 config->magic_0 = rdp->magic_0 - 1;
 1319             config->magic_1 = rdp->magic_1;
 1320             break;
 1321 
 1322         case AR_F_SPAN:
 1323             config->type = HPT_T_SPAN;
 1324             strcpy(config->name_2, "SPAN");
 1325             break;
 1326         }
 1327 
 1328         config->array_width = rdp->width;
 1329         config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0;
 1330         config->total_sectors = rdp->total_sectors;
 1331         config->rebuild_lba = rdp->lock_start;
 1332 
 1333         if (rdp->disks[disk].device && rdp->disks[disk].device->softc &&
 1334             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
 1335             if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA,
 1336                       sizeof(struct highpoint_raid_conf),
 1337                       (caddr_t)config, AR_WRITE)) {
 1338                 printf("ar%d: Highpoint write conf failed\n", rdp->lun);
 1339                 free(config, M_AR);
 1340                 return -1;
 1341             }
 1342         }
 1343         else
 1344             free(config, M_AR);
 1345     }
 1346     return 0;
 1347 }
 1348 
 1349 static int
 1350 ar_lsi_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
 1351 {
 1352     struct lsi_raid_conf *info;
 1353     struct ar_softc *raid = NULL;
 1354     int array, retval = 0;
 1355 
 1356     if (!(info = (struct lsi_raid_conf *)
 1357           malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
 1358         return retval;
 1359 
 1360     if (ar_rw(adp, LSI_LBA(adp), sizeof(struct lsi_raid_conf),
 1361               (caddr_t)info, AR_READ | AR_WAIT)) {
 1362         if (bootverbose)
 1363             printf("ar: LSI read conf failed\n");
 1364         goto lsi_out;
 1365     }
 1366 
 1367     /* check if this is a LSI RAID struct */
 1368     if (strncmp(info->lsi_id, LSI_MAGIC, strlen(LSI_MAGIC))) {
 1369         if (bootverbose)
 1370             printf("ar: LSI check1 failed\n");
 1371         goto lsi_out;
 1372     }
 1373 
 1374     /* now convert LSI config info into our generic form */
 1375     for (array = 0; array < MAX_ARRAYS; array++) {
 1376         int raid_entry, conf_entry;
 1377 
 1378         if (!raidp[array + info->raid_number]) {
 1379             raidp[array + info->raid_number] = 
 1380                 (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
 1381                                          M_NOWAIT | M_ZERO);
 1382             if (!raidp[array + info->raid_number]) {
 1383                 printf("ar%d: failed to allocate raid config storage\n", array);
 1384                 goto lsi_out;
 1385             }
 1386         }
 1387         raid = raidp[array + info->raid_number];
 1388 
 1389         if (raid->flags & (AR_F_PROMISE_RAID | AR_F_HIGHPOINT_RAID))
 1390             continue;
 1391 
 1392         if (raid->magic_0 && 
 1393             ((raid->magic_0 != info->timestamp) ||
 1394              (raid->magic_1 != info->raid_number)))
 1395             continue;
 1396 
 1397         array += info->raid_number;
 1398 
 1399         raid_entry = info->raid_number;
 1400         conf_entry = (info->configs[raid_entry].raid.config_offset >> 4) +
 1401                      info->disk_number - 1;
 1402 
 1403         switch (info->configs[raid_entry].raid.type) {
 1404         case LSI_R_RAID0:
 1405             raid->magic_0 = info->timestamp;
 1406             raid->magic_1 = info->raid_number;
 1407             raid->flags |= AR_F_RAID0;
 1408             raid->interleave = info->configs[raid_entry].raid.stripe_size;
 1409             raid->width = info->configs[raid_entry].raid.raid_width; 
 1410             break;
 1411 
 1412         case LSI_R_RAID1:
 1413             raid->magic_0 = info->timestamp;
 1414             raid->magic_1 = info->raid_number;
 1415             raid->flags |= AR_F_RAID1;
 1416             raid->width = info->configs[raid_entry].raid.raid_width; 
 1417             break;
 1418             
 1419         case LSI_R_RAID0 | LSI_R_RAID1:
 1420             raid->magic_0 = info->timestamp;
 1421             raid->magic_1 = info->raid_number;
 1422             raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
 1423             raid->interleave = info->configs[raid_entry].raid.stripe_size;
 1424             raid->width = info->configs[raid_entry].raid.raid_width; 
 1425             break;
 1426 
 1427         default:
 1428             printf("ar%d: LSI unknown RAID type 0x%02x\n",
 1429                    array, info->configs[raid_entry].raid.type);
 1430             free(raidp[array], M_AR);
 1431             raidp[array] = NULL;
 1432             goto lsi_out;
 1433         }
 1434 
 1435         /* setup RAID specifics */
 1436         raid->flags |= AR_F_LSI_RAID;
 1437         raid->generation = 0;
 1438         raid->total_disks = info->configs[raid_entry].raid.disk_count;
 1439         raid->heads = 255;
 1440         raid->sectors = 63;
 1441         raid->cylinders = info->configs[raid_entry].raid.total_sectors/(63*255);
 1442         raid->total_sectors = info->configs[raid_entry].raid.total_sectors;
 1443         raid->offset = 0;
 1444         raid->reserved = 1;
 1445         raid->lock_start = raid->lock_end = 0;
 1446         raid->lun = array;
 1447 
 1448         /* setup RAID specifics of this disk */
 1449         if (info->configs[conf_entry].disk.device != LSI_D_NONE) {
 1450             raid->disks[info->disk_number].device = adp->device;
 1451             raid->disks[info->disk_number].disk_sectors = 
 1452                 info->configs[conf_entry].disk.disk_sectors;
 1453             raid->disks[info->disk_number].flags = 
 1454                 (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
 1455             AD_SOFTC(raid->disks[info->disk_number])->flags |=
 1456                 AD_F_RAID_SUBDISK;
 1457             retval = 1;
 1458         }
 1459         else
 1460             raid->disks[info->disk_number].flags &= ~AR_DF_ONLINE;
 1461 
 1462         return retval;
 1463     }
 1464 
 1465 lsi_out:
 1466     free(info, M_AR);
 1467     return retval;
 1468 }
 1469 
 1470 static int
 1471 ar_lsi_write_conf(struct ar_softc *rdp)
 1472 {
 1473     struct lsi_raid_conf *config;
 1474     struct timeval timestamp;
 1475     int disk, disk_entry;
 1476 
 1477     microtime(&timestamp);
 1478     rdp->magic_0 = timestamp.tv_sec & 0xffffffc0;
 1479     rdp->magic_1 = 0;
 1480    
 1481     for (disk = 0; disk < rdp->total_disks; disk++) {
 1482         if (!(config = (struct lsi_raid_conf *)
 1483               malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO))) {
 1484             printf("ar%d: LSI write conf failed\n", rdp->lun);
 1485             return -1;
 1486         }
 1487 
 1488         bcopy(LSI_MAGIC, config->lsi_id, strlen(LSI_MAGIC));
 1489         config->dummy_1 = 0x10;
 1490         config->flags = 0x19;           /* SOS X */
 1491         config->version[0] = '2';
 1492         config->version[1] = '';
 1493         config->config_entries = 2 + rdp->total_disks;
 1494         config->raid_count = 1;
 1495         config->total_disks = rdp->total_disks;
 1496         config->dummy_e = 0xfc;
 1497         config->disk_number = disk;
 1498         config->raid_number = 0;
 1499         config->timestamp = rdp->magic_0;
 1500         
 1501         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
 1502         case AR_F_RAID0:
 1503             config->configs[0].raid.type = LSI_R_RAID0;
 1504             break;
 1505 
 1506         case AR_F_RAID1:
 1507             config->configs[0].raid.type = LSI_R_RAID1;
 1508             break;
 1509 
 1510         case AR_F_RAID0 | AR_F_RAID1:
 1511             config->flags = 0x15;               /* SOS X */
 1512             config->configs[0].raid.type = (LSI_R_RAID0 | LSI_R_RAID1);
 1513             break;
 1514 
 1515         default:
 1516             free(config, M_AR);
 1517             return -1;
 1518         }
 1519 
 1520         config->configs[0].raid.dummy_1 = 0x10;
 1521         config->configs[0].raid.stripe_size = rdp->interleave;
 1522         config->configs[0].raid.raid_width = rdp->width;
 1523         config->configs[0].raid.disk_count = rdp->total_disks;
 1524         config->configs[0].raid.config_offset = 2 * 0x10;
 1525         config->configs[0].raid.total_sectors = rdp->total_sectors;
 1526 
 1527         for (disk_entry = 0; disk_entry < rdp->total_disks; disk_entry++) {
 1528             if (rdp->disks[disk_entry].flags & AR_DF_ONLINE)
 1529                 config->configs[1 + disk_entry].disk.device = 
 1530                     (rdp->disks[disk_entry].device->channel->unit ? 
 1531                         LSI_D_CHANNEL1 : LSI_D_CHANNEL0) |
 1532                     (rdp->disks[disk_entry].device->unit ?
 1533                         LSI_D_SLAVE : LSI_D_MASTER);
 1534             else {
 1535                 config->configs[1 + disk_entry].disk.device = LSI_D_NONE;
 1536                 config->configs[1 + disk_entry].disk.flags = LSI_D_GONE;
 1537             }
 1538             config->configs[1 + disk_entry].disk.dummy_1 = 0x10;
 1539             config->configs[1 + disk_entry].disk.disk_sectors = 
 1540                 rdp->disks[disk_entry].disk_sectors;
 1541             config->configs[1 + disk_entry].disk.disk_number = disk_entry;
 1542             config->configs[1 + disk_entry].disk.raid_number = 0;
 1543         }
 1544 
 1545         if ((rdp->disks[disk].device && rdp->disks[disk].device->softc) &&
 1546             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
 1547 
 1548             if (ar_rw(AD_SOFTC(rdp->disks[disk]),
 1549                       LSI_LBA(AD_SOFTC(rdp->disks[disk])),
 1550                       sizeof(struct lsi_raid_conf),
 1551                       (caddr_t)config, AR_WRITE)) {
 1552                 printf("ar%d: LSI write conf failed\n", rdp->lun);
 1553                 free(config, M_AR);
 1554                 return -1;
 1555             }
 1556         }
 1557         else
 1558             free(config, M_AR);
 1559     }
 1560     return 0;
 1561 }
 1562 
 1563 static int
 1564 ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
 1565 {
 1566     struct promise_raid_conf *info;
 1567     struct ar_softc *raid;
 1568     u_int32_t magic, cksum, *ckptr;
 1569     int array, count, disk, disksum = 0, retval = 0; 
 1570 
 1571     if (!(info = (struct promise_raid_conf *)
 1572           malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
 1573         return retval;
 1574 
 1575     if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
 1576               (caddr_t)info, AR_READ | AR_WAIT)) {
 1577         if (bootverbose)
 1578             printf("ar: %s read conf failed\n", local ? "FreeBSD" : "Promise");
 1579         goto promise_out;
 1580     }
 1581 
 1582     /* check if this is a Promise RAID struct (or our local one) */
 1583     if (local) {
 1584         if (strncmp(info->promise_id, ATA_MAGIC, strlen(ATA_MAGIC))) {
 1585             if (bootverbose)
 1586                 printf("ar: FreeBSD check1 failed\n");
 1587             goto promise_out;
 1588         }
 1589     }
 1590     else {
 1591         if (strncmp(info->promise_id, PR_MAGIC, strlen(PR_MAGIC))) {
 1592             if (bootverbose)
 1593                 printf("ar: Promise check1 failed\n");
 1594             goto promise_out;
 1595         }
 1596     }
 1597 
 1598     /* check if the checksum is OK */
 1599     for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++)
 1600         cksum += *ckptr++;
 1601     if (cksum != *ckptr) {  
 1602         if (bootverbose)
 1603             printf("ar: %s check2 failed\n", local ? "FreeBSD" : "Promise");         
 1604         goto promise_out;
 1605     }
 1606 
 1607     /* now convert Promise config info into our generic form */
 1608     if (info->raid.integrity != PR_I_VALID) {
 1609         if (bootverbose)
 1610             printf("ar: %s check3 failed\n", local ? "FreeBSD" : "Promise");         
 1611         goto promise_out;
 1612     }
 1613 
 1614     for (array = 0; array < MAX_ARRAYS; array++) {
 1615         if (!raidp[array]) {
 1616             raidp[array] = 
 1617                 (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR,
 1618                                          M_NOWAIT | M_ZERO);
 1619             if (!raidp[array]) {
 1620                 printf("ar%d: failed to allocate raid config storage\n", array);
 1621                 goto promise_out;
 1622             }
 1623         }
 1624         raid = raidp[array];
 1625         if (raid->flags & (AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID))
 1626             continue;
 1627 
 1628         magic = (pci_get_device(device_get_parent(
 1629                                 adp->device->channel->dev)) >> 16) |
 1630                 (info->raid.array_number << 16);
 1631 
 1632         if (raid->flags & AR_F_PROMISE_RAID && magic != raid->magic_0)
 1633             continue;
 1634 
 1635         /* update our knowledge about the array config based on generation */
 1636         if (!info->raid.generation || info->raid.generation > raid->generation){
 1637             raid->generation = info->raid.generation;
 1638             raid->flags = AR_F_PROMISE_RAID;
 1639             if (local)
 1640                 raid->flags |= AR_F_FREEBSD_RAID;
 1641             raid->magic_0 = magic;
 1642             raid->lun = array;
 1643             if ((info->raid.status &
 1644                  (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) ==
 1645                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) {
 1646                 raid->flags |= AR_F_READY;
 1647                 if (info->raid.status & PR_S_DEGRADED)
 1648                     raid->flags |= AR_F_DEGRADED;
 1649             }
 1650             else
 1651                 raid->flags &= ~AR_F_READY;
 1652 
 1653             switch (info->raid.type) {
 1654             case PR_T_RAID0:
 1655                 raid->flags |= AR_F_RAID0;
 1656                 break;
 1657 
 1658             case PR_T_RAID1:
 1659                 raid->flags |= AR_F_RAID1;
 1660                 if (info->raid.array_width > 1)
 1661                     raid->flags |= AR_F_RAID0;
 1662                 break;
 1663 
 1664             case PR_T_SPAN:
 1665                 raid->flags |= AR_F_SPAN;
 1666                 break;
 1667 
 1668             default:
 1669                 printf("ar%d: %s unknown RAID type 0x%02x\n",
 1670                        array, local ? "FreeBSD" : "Promise", info->raid.type);
 1671                 free(raidp[array], M_AR);
 1672                 raidp[array] = NULL;
 1673                 goto promise_out;
 1674             }
 1675             raid->interleave = 1 << info->raid.stripe_shift;
 1676             raid->width = info->raid.array_width;
 1677             raid->total_disks = info->raid.total_disks;
 1678             raid->heads = info->raid.heads + 1;
 1679             raid->sectors = info->raid.sectors;
 1680             raid->cylinders = info->raid.cylinders + 1;
 1681             raid->total_sectors = info->raid.total_sectors;
 1682             raid->offset = 0;
 1683             raid->reserved = 63;
 1684             raid->lock_start = raid->lock_end = info->raid.rebuild_lba;
 1685 
 1686             /* convert disk flags to our internal types */
 1687             for (disk = 0; disk < info->raid.total_disks; disk++) {
 1688                 raid->disks[disk].flags = 0;
 1689                 disksum += info->raid.disk[disk].flags;
 1690                 if (info->raid.disk[disk].flags & PR_F_ONLINE)
 1691                     raid->disks[disk].flags |= AR_DF_ONLINE;
 1692                 if (info->raid.disk[disk].flags & PR_F_ASSIGNED)
 1693                     raid->disks[disk].flags |= AR_DF_ASSIGNED;
 1694                 if (info->raid.disk[disk].flags & PR_F_SPARE) {
 1695                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
 1696                     raid->disks[disk].flags |= AR_DF_SPARE;
 1697                 }
 1698                 if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN))
 1699                     raid->disks[disk].flags &= ~AR_DF_ONLINE;
 1700             }
 1701             if (!disksum) {
 1702                 free(raidp[array], M_AR);
 1703                 raidp[array] = NULL;
 1704                 goto promise_out;
 1705             }
 1706         }
 1707         if (info->raid.generation >= raid->generation) {
 1708             if (raid->disks[info->raid.disk_number].flags && adp->device) {
 1709                 raid->disks[info->raid.disk_number].device = adp->device;
 1710                 raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT;
 1711                 raid->disks[info->raid.disk_number].disk_sectors =
 1712                     info->raid.disk_sectors;
 1713                 if ((raid->disks[info->raid.disk_number].flags &
 1714                     (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) ==
 1715                     (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) {
 1716                     AD_SOFTC(raid->disks[info->raid.disk_number])->flags |=
 1717                         AD_F_RAID_SUBDISK;
 1718                     retval = 1;
 1719                 }
 1720             }
 1721         }
 1722         break;
 1723     }
 1724 promise_out:
 1725     free(info, M_AR);
 1726     return retval;
 1727 }
 1728 
 1729 static int
 1730 ar_promise_write_conf(struct ar_softc *rdp)
 1731 {
 1732     struct promise_raid_conf *config;
 1733     struct timeval timestamp;
 1734     u_int32_t *ckptr;
 1735     int count, disk, drive;
 1736     int local = rdp->flags & AR_F_FREEBSD_RAID;
 1737 
 1738     rdp->generation++;
 1739     microtime(&timestamp);
 1740 
 1741     for (disk = 0; disk < rdp->total_disks; disk++) {
 1742         if (!(config = (struct promise_raid_conf *)
 1743               malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) {
 1744             printf("ar%d: %s write conf failed\n",
 1745                    rdp->lun, local ? "FreeBSD" : "Promise");
 1746             return -1;
 1747         }
 1748         for (count = 0; count < sizeof(struct promise_raid_conf); count++)
 1749             *(((u_int8_t *)config) + count) = 255 - (count % 256);
 1750 
 1751         config->dummy_0 = 0x00020000;
 1752         config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec;
 1753         config->magic_1 = timestamp.tv_sec >> 16;
 1754         config->magic_2 = timestamp.tv_sec;
 1755         config->raid.integrity = PR_I_VALID;
 1756 
 1757         config->raid.disk_number = disk;
 1758         if (rdp->disks[disk].flags & AR_DF_PRESENT && rdp->disks[disk].device) {
 1759             config->raid.channel = rdp->disks[disk].device->channel->unit;
 1760             config->raid.device = (rdp->disks[disk].device->unit != 0);
 1761             if (rdp->disks[disk].device->softc)
 1762                 config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk]));
 1763             /*config->raid.disk_offset*/
 1764         }
 1765         config->raid.magic_0 = config->magic_0;
 1766         config->raid.rebuild_lba = rdp->lock_start;
 1767         config->raid.generation = rdp->generation;
 1768 
 1769         if (rdp->flags & AR_F_READY) {
 1770             config->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE);
 1771             config->raid.status = 
 1772                 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY);
 1773             if (rdp->flags & AR_F_DEGRADED)
 1774                 config->raid.status |= PR_S_DEGRADED;
 1775             else
 1776                 config->raid.status |= PR_S_FUNCTIONAL;
 1777         }
 1778         else {
 1779             config->raid.flags = PR_F_DOWN;
 1780             config->raid.status = 0;
 1781         }
 1782 
 1783         switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
 1784         case AR_F_RAID0:
 1785             config->raid.type = PR_T_RAID0;
 1786             break;
 1787         case AR_F_RAID1:
 1788             config->raid.type = PR_T_RAID1;
 1789             break;
 1790         case AR_F_RAID0 | AR_F_RAID1:
 1791             config->raid.type = PR_T_RAID1;
 1792             break;
 1793         case AR_F_SPAN:
 1794             config->raid.type = PR_T_SPAN;
 1795             break;
 1796         }
 1797 
 1798         config->raid.total_disks = rdp->total_disks;
 1799         config->raid.stripe_shift = ffs(rdp->interleave) - 1;
 1800         config->raid.array_width = rdp->width;
 1801         config->raid.array_number = rdp->lun;
 1802         config->raid.total_sectors = rdp->total_sectors;
 1803         config->raid.cylinders = rdp->cylinders - 1;
 1804         config->raid.heads = rdp->heads - 1;
 1805         config->raid.sectors = rdp->sectors;
 1806         config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1;
 1807 
 1808         bzero(&config->raid.disk, 8 * 12);
 1809         for (drive = 0; drive < rdp->total_disks; drive++) {
 1810             config->raid.disk[drive].flags = 0;
 1811             if (rdp->disks[drive].flags & AR_DF_PRESENT)
 1812                 config->raid.disk[drive].flags |= PR_F_VALID;
 1813             if (rdp->disks[drive].flags & AR_DF_ASSIGNED)
 1814                 config->raid.disk[drive].flags |= PR_F_ASSIGNED;
 1815             if (rdp->disks[drive].flags & AR_DF_ONLINE)
 1816                 config->raid.disk[drive].flags |= PR_F_ONLINE;
 1817             else
 1818                 if (rdp->disks[drive].flags & AR_DF_PRESENT)
 1819                     config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN);
 1820             if (rdp->disks[drive].flags & AR_DF_SPARE)
 1821                 config->raid.disk[drive].flags |= PR_F_SPARE;
 1822             config->raid.disk[drive].dummy_0 = 0x0;
 1823             if (rdp->disks[drive].device) {
 1824                 config->raid.disk[drive].channel =
 1825                     rdp->disks[drive].device->channel->unit;
 1826                 config->raid.disk[drive].device =
 1827                     (rdp->disks[drive].device->unit != 0);
 1828             }
 1829             config->raid.disk[drive].magic_0 =
 1830                 PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec;
 1831         }
 1832 
 1833         if (rdp->disks[disk].device && rdp->disks[disk].device->softc &&
 1834             !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
 1835             if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
 1836                 (AR_DF_PRESENT | AR_DF_ONLINE)) {
 1837                 if (local)
 1838                     bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC));
 1839                 else
 1840                     bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC));
 1841             }
 1842             else
 1843                 bzero(config->promise_id, sizeof(config->promise_id));
 1844             config->checksum = 0;
 1845             for (ckptr = (int32_t *)config, count = 0; count < 511; count++)
 1846                 config->checksum += *ckptr++;
 1847             if (ar_rw(AD_SOFTC(rdp->disks[disk]),
 1848                       PR_LBA(AD_SOFTC(rdp->disks[disk])),
 1849                       sizeof(struct promise_raid_conf),
 1850                       (caddr_t)config, AR_WRITE)) {
 1851                 printf("ar%d: %s write conf failed\n",
 1852                        rdp->lun, local ? "FreeBSD" : "Promise");
 1853                 free(config, M_AR);
 1854                 return -1;
 1855             }
 1856         }
 1857         else
 1858             free(config, M_AR);
 1859     }
 1860     return 0;
 1861 }
 1862 
 1863 static void
 1864 ar_rw_done(struct bio *bp)
 1865 {
 1866     free(bp->bio_data, M_AR);
 1867     free(bp, M_AR);
 1868 }
 1869 
 1870 static int
 1871 ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags)
 1872 {
 1873     struct bio *bp;
 1874     int retry = 0, error = 0;
 1875 
 1876     if (!(bp = (struct bio *)malloc(sizeof(struct bio), M_AR, M_NOWAIT|M_ZERO)))
 1877         return 1;
 1878     bp->bio_disk = adp->disk;
 1879     bp->bio_data = data;
 1880     bp->bio_pblkno = lba;
 1881     bp->bio_bcount = count;
 1882     if (flags & AR_READ)
 1883         bp->bio_cmd = BIO_READ;
 1884     if (flags & AR_WRITE)
 1885         bp->bio_cmd = BIO_WRITE;
 1886     if (flags & AR_WAIT)
 1887         bp->bio_done = (void *)wakeup;
 1888     else
 1889         bp->bio_done = ar_rw_done;
 1890 
 1891     AR_STRATEGY(bp);
 1892 
 1893     if (flags & AR_WAIT) {
 1894         while ((retry++ < (15*hz/10)) && (error = !(bp->bio_flags & BIO_DONE)))
 1895             error = tsleep(bp, PRIBIO, "arrw", 10);
 1896         if (!error && bp->bio_flags & BIO_ERROR)
 1897             error = bp->bio_error;
 1898         free(bp, M_AR);
 1899     }
 1900     return error;
 1901 }
 1902 
 1903 static struct ata_device *
 1904 ar_locate_disk(int diskno)
 1905 {
 1906     struct ata_channel *ch;
 1907     int ctlr;
 1908 
 1909     for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
 1910         if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
 1911             continue;
 1912         if (ch->devices & ATA_ATA_MASTER)
 1913             if (ch->device[MASTER].softc &&
 1914                 ((struct ad_softc *)(ch->device[MASTER].softc))->lun == diskno)
 1915                 return &ch->device[MASTER];
 1916         if (ch->devices & ATA_ATA_SLAVE)
 1917             if (ch->device[SLAVE].softc &&
 1918                 ((struct ad_softc *)(ch->device[SLAVE].softc))->lun == diskno)
 1919                 return &ch->device[SLAVE];
 1920     }
 1921     return NULL;
 1922 }
 1923 
 1924 static void
 1925 ar_print_conf(struct ar_softc *config)
 1926 {
 1927     int i;
 1928 
 1929     printf("lun         %d\n", config->lun);
 1930     printf("magic_0             0x%08x\n", config->magic_0);
 1931     printf("magic_1             0x%08x\n", config->magic_1);
 1932     printf("flags               0x%02x %b\n", config->flags, config->flags,
 1933         "\2\16HIGHPOINT\15PROMISE\13REBUILDING\12DEGRADED\11READY\3SPAN\2RAID1\1RAID0\n");
 1934     printf("total_disks %d\n", config->total_disks);
 1935     printf("generation  %d\n", config->generation);
 1936     printf("width               %d\n", config->width);
 1937     printf("heads               %d\n", config->heads);
 1938     printf("sectors             %d\n", config->sectors);
 1939     printf("cylinders   %d\n", config->cylinders);
 1940     printf("total_sectors       %lld\n", (long long)config->total_sectors);
 1941     printf("interleave  %d\n", config->interleave);
 1942     printf("reserved    %d\n", config->reserved);
 1943     printf("offset              %d\n", config->offset);
 1944     for (i = 0; i < config->total_disks; i++) {
 1945         printf("disk %d:        flags = 0x%02x %b\n", i, config->disks[i].flags, config->disks[i].flags, "\2\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n");
 1946         if (config->disks[i].device)
 1947             printf("    %s\n", config->disks[i].device->name);
 1948         printf("        sectors %lld\n", (long long)config->disks[i].disk_sectors);
 1949     }
 1950 }

Cache object: 128dd5ed7b47981e714384657c12dfd8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.