Rename printf -> kprintf in sys/ and add some defines where necessary
[dragonfly/vkernel-mp.git] / sys / dev / disk / ata / ata-raid.c
blobac01ce96bcbaec84265dbe3850c95b93ee4b98b8
1 /*-
2 * Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
3 * All rights reserved.
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.
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.
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.25 2006/12/23 00:26:15 swildner Exp $
32 #include "opt_ata.h"
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/ata.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/buf.h>
39 #include <sys/bus.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/devicestat.h>
43 #include <sys/cons.h>
44 #include <sys/rman.h>
45 #include <sys/proc.h>
46 #include <sys/buf2.h>
47 #include <sys/thread2.h>
49 #include "ata-all.h"
50 #include "ata-disk.h"
51 #include "ata-raid.h"
53 /* device structures */
54 static d_open_t aropen;
55 static d_strategy_t arstrategy;
57 static struct dev_ops ar_ops = {
58 { "ar", 157, D_DISK },
59 .d_open = aropen,
60 .d_close = nullclose,
61 .d_read = physread,
62 .d_write = physwrite,
63 .d_strategy = arstrategy,
64 };
66 /* prototypes */
67 static void ar_attach_raid(struct ar_softc *, int);
68 static void ar_done(struct bio *);
69 static void ar_sync_done(struct bio *);
70 static void ar_config_changed(struct ar_softc *, int);
71 static int ar_rebuild(struct ar_softc *);
72 static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **);
73 static int ar_highpoint_write_conf(struct ar_softc *);
74 static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int);
75 static int ar_promise_write_conf(struct ar_softc *);
76 static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int);
77 static struct ata_device *ar_locate_disk(int);
79 /* internal vars */
80 static struct ar_softc **ar_table = NULL;
81 static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver");
83 int
84 ata_raiddisk_attach(struct ad_softc *adp)
86 struct ar_softc *rdp;
87 int array, disk;
89 if (ar_table) {
90 for (array = 0; array < MAX_ARRAYS; array++) {
91 if (!(rdp = ar_table[array]) || !rdp->flags)
92 continue;
94 for (disk = 0; disk < rdp->total_disks; disk++) {
95 if ((rdp->disks[disk].flags & AR_DF_ASSIGNED) &&
96 rdp->disks[disk].device == adp->device) {
97 ata_prtdev(rdp->disks[disk].device,
98 "inserted into ar%d disk%d as spare\n",
99 array, disk);
100 rdp->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_SPARE);
101 AD_SOFTC(rdp->disks[disk])->flags = AD_F_RAID_SUBDISK;
102 ar_config_changed(rdp, 1);
103 return 1;
109 if (!ar_table) {
110 ar_table = kmalloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
111 M_AR, M_WAITOK | M_ZERO);
114 switch(adp->device->channel->chiptype) {
115 case 0x4d33105a: case 0x4d38105a: case 0x4d30105a:
116 case 0x0d30105a: case 0x4d68105a: case 0x6268105a:
117 case 0x4d69105a: case 0x5275105a: case 0x6269105a:
118 case 0x7275105a:
119 /* test RAID bit in PCI reg XXX */
120 return (ar_promise_read_conf(adp, ar_table, 0));
122 case 0x00041103: case 0x00051103: case 0x00081103:
123 return (ar_highpoint_read_conf(adp, ar_table));
125 default:
126 return (ar_promise_read_conf(adp, ar_table, 1));
128 return 0;
132 ata_raiddisk_detach(struct ad_softc *adp)
134 struct ar_softc *rdp;
135 int array, disk;
137 if (ar_table) {
138 for (array = 0; array < MAX_ARRAYS; array++) {
139 if (!(rdp = ar_table[array]) || !rdp->flags)
140 continue;
141 for (disk = 0; disk < rdp->total_disks; disk++) {
142 if (rdp->disks[disk].device == adp->device) {
143 ata_prtdev(rdp->disks[disk].device,
144 "deleted from ar%d disk%d\n", array, disk);
145 rdp->disks[disk].flags &= ~(AR_DF_PRESENT | AR_DF_ONLINE);
146 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
147 ar_config_changed(rdp, 1);
148 return 1;
153 return 0;
156 void
157 ata_raid_attach()
159 struct ar_softc *rdp;
160 int array;
162 if (!ar_table)
163 return;
165 for (array = 0; array < MAX_ARRAYS; array++) {
166 if (!(rdp = ar_table[array]) || !rdp->flags)
167 continue;
168 ar_attach_raid(rdp, 0);
172 static void
173 ar_attach_raid(struct ar_softc *rdp, int update)
175 cdev_t dev;
176 int disk;
178 ar_config_changed(rdp, update);
179 dev = disk_create(rdp->lun, &rdp->disk, 0, &ar_ops);
180 dev->si_drv1 = rdp;
181 dev->si_iosize_max = 256 * DEV_BSIZE;
182 rdp->dev = dev;
184 kprintf("ar%d: %lluMB <ATA ", rdp->lun, (unsigned long long)
185 (rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE)));
186 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
187 case AR_F_RAID0:
188 kprintf("RAID0 "); break;
189 case AR_F_RAID1:
190 kprintf("RAID1 "); break;
191 case AR_F_SPAN:
192 kprintf("SPAN "); break;
193 case (AR_F_RAID0 | AR_F_RAID1):
194 kprintf("RAID0+1 "); break;
195 default:
196 kprintf("unknown 0x%x> ", rdp->flags);
197 return;
199 kprintf("array> [%d/%d/%d] status: ",
200 rdp->cylinders, rdp->heads, rdp->sectors);
201 switch (rdp->flags & (AR_F_DEGRADED | AR_F_READY)) {
202 case AR_F_READY:
203 kprintf("READY");
204 break;
205 case (AR_F_DEGRADED | AR_F_READY):
206 kprintf("DEGRADED");
207 break;
208 default:
209 kprintf("BROKEN");
210 break;
212 kprintf(" subdisks:\n");
213 for (disk = 0; disk < rdp->total_disks; disk++) {
214 if (rdp->disks[disk].flags & AR_DF_PRESENT) {
215 if (rdp->disks[disk].flags & AR_DF_ONLINE)
216 kprintf(" %d READY ", disk);
217 else if (rdp->disks[disk].flags & AR_DF_SPARE)
218 kprintf(" %d SPARE ", disk);
219 else
220 kprintf(" %d FREE ", disk);
221 ad_print(AD_SOFTC(rdp->disks[disk]));
222 kprintf(" ");
223 ata_enclosure_print(AD_SOFTC(rdp->disks[disk])->device);
225 else if (rdp->disks[disk].flags & AR_DF_ASSIGNED)
226 kprintf(" %d DOWN\n", disk);
227 else
228 kprintf(" %d INVALID no RAID config info on this disk\n", disk);
233 ata_raid_create(struct raid_setup *setup)
235 struct ata_device *atadev;
236 struct ar_softc *rdp;
237 int array, disk;
238 int ctlr = 0, disk_size = 0, total_disks = 0;
240 if (!ar_table) {
241 ar_table = kmalloc(sizeof(struct ar_soft *) * MAX_ARRAYS,
242 M_AR, M_WAITOK | M_ZERO);
244 for (array = 0; array < MAX_ARRAYS; array++) {
245 if (!ar_table[array])
246 break;
248 if (array >= MAX_ARRAYS)
249 return ENOSPC;
251 rdp = kmalloc(sizeof(struct ar_softc), M_AR, M_WAITOK | M_ZERO);
253 for (disk = 0; disk < setup->total_disks; disk++) {
254 if ((atadev = ar_locate_disk(setup->disks[disk]))) {
255 rdp->disks[disk].device = atadev;
256 if (AD_SOFTC(rdp->disks[disk])->flags & AD_F_RAID_SUBDISK) {
257 setup->disks[disk] = -1;
258 kfree(rdp, M_AR);
259 return EBUSY;
262 switch (rdp->disks[disk].device->channel->chiptype & 0xffff) {
263 case 0x1103:
264 ctlr |= AR_F_HIGHPOINT_RAID;
265 rdp->disks[disk].disk_sectors =
266 AD_SOFTC(rdp->disks[disk])->total_secs;
267 break;
269 default:
270 ctlr |= AR_F_FREEBSD_RAID;
271 /* FALLTHROUGH */
273 case 0x105a:
274 ctlr |= AR_F_PROMISE_RAID;
275 rdp->disks[disk].disk_sectors =
276 PR_LBA(AD_SOFTC(rdp->disks[disk]));
277 break;
279 if ((rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) &&
280 (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) !=
281 (ctlr & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID))) {
282 kfree(rdp, M_AR);
283 return EXDEV;
285 else
286 rdp->flags |= ctlr;
288 if (disk_size)
289 disk_size = min(rdp->disks[disk].disk_sectors, disk_size);
290 else
291 disk_size = rdp->disks[disk].disk_sectors;
292 rdp->disks[disk].flags =
293 (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE);
295 total_disks++;
297 else {
298 setup->disks[disk] = -1;
299 kfree(rdp, M_AR);
300 return ENXIO;
303 if (!total_disks) {
304 kfree(rdp, M_AR);
305 return ENODEV;
308 switch (setup->type) {
309 case 1:
310 rdp->flags |= AR_F_RAID0;
311 break;
312 case 2:
313 rdp->flags |= AR_F_RAID1;
314 if (total_disks != 2) {
315 kfree(rdp, M_AR);
316 return EPERM;
318 break;
319 case 3:
320 rdp->flags |= (AR_F_RAID0 | AR_F_RAID1);
321 if (total_disks % 2 != 0) {
322 kfree(rdp, M_AR);
323 return EPERM;
325 break;
326 case 4:
327 rdp->flags |= AR_F_SPAN;
328 break;
331 for (disk = 0; disk < total_disks; disk++)
332 AD_SOFTC(rdp->disks[disk])->flags = AD_F_RAID_SUBDISK;
334 rdp->lun = array;
335 if (rdp->flags & AR_F_RAID0) {
336 int bit = 0;
338 while (setup->interleave >>= 1)
339 bit++;
340 if (rdp->flags & AR_F_PROMISE_RAID)
341 rdp->interleave = min(max(2, 1 << bit), 2048);
342 if (rdp->flags & AR_F_HIGHPOINT_RAID)
343 rdp->interleave = min(max(32, 1 << bit), 128);
345 rdp->total_disks = total_disks;
346 rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1);
347 rdp->total_sectors = disk_size * rdp->width;
348 rdp->heads = 255;
349 rdp->sectors = 63;
350 rdp->cylinders = rdp->total_sectors / (255 * 63);
351 if (rdp->flags & AR_F_PROMISE_RAID) {
352 rdp->offset = 0;
353 rdp->reserved = 63;
355 if (rdp->flags & AR_F_HIGHPOINT_RAID) {
356 rdp->offset = HPT_LBA + 1;
357 rdp->reserved = HPT_LBA + 1;
359 rdp->lock_start = rdp->lock_end = 0xffffffff;
360 rdp->flags |= AR_F_READY;
362 ar_table[array] = rdp;
363 ar_attach_raid(rdp, 1);
364 setup->unit = array;
365 return 0;
369 ata_raid_delete(int array)
371 struct ar_softc *rdp;
372 int disk;
374 if (!ar_table) {
375 kprintf("ar: no memory for ATA raid array\n");
376 return 0;
378 if (!(rdp = ar_table[array]))
379 return ENXIO;
381 rdp->flags &= ~AR_F_READY;
382 for (disk = 0; disk < rdp->total_disks; disk++) {
383 if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
384 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
385 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
386 rdp->disks[disk].flags = 0;
389 if (rdp->flags & AR_F_PROMISE_RAID)
390 ar_promise_write_conf(rdp);
391 else
392 ar_highpoint_write_conf(rdp);
393 disk_invalidate(&rdp->disk);
394 disk_destroy(&rdp->disk);
395 kfree(rdp, M_AR);
396 ar_table[array] = NULL;
397 return 0;
401 ata_raid_status(int array, struct raid_status *status)
403 struct ar_softc *rdp;
404 int i;
406 if (!ar_table || !(rdp = ar_table[array]))
407 return ENXIO;
409 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
410 case AR_F_RAID0:
411 status->type = AR_RAID0;
412 break;
413 case AR_F_RAID1:
414 status->type = AR_RAID1;
415 break;
416 case AR_F_RAID0 | AR_F_RAID1:
417 status->type = AR_RAID0 | AR_RAID1;
418 break;
419 case AR_F_SPAN:
420 status->type = AR_SPAN;
421 break;
423 status->total_disks = rdp->total_disks;
424 for (i = 0; i < rdp->total_disks; i++ ) {
425 if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].device)
426 status->disks[i] = AD_SOFTC(rdp->disks[i])->lun;
427 else
428 status->disks[i] = -1;
430 status->interleave = rdp->interleave;
431 status->status = 0;
432 if (rdp->flags & AR_F_READY)
433 status->status |= AR_READY;
434 if (rdp->flags & AR_F_DEGRADED)
435 status->status |= AR_DEGRADED;
436 if (rdp->flags & AR_F_REBUILDING) {
437 status->status |= AR_REBUILDING;
438 status->progress = 100*rdp->lock_start/(rdp->total_sectors/rdp->width);
440 return 0;
444 ata_raid_rebuild(int array)
446 struct ar_softc *rdp;
448 if (!ar_table || !(rdp = ar_table[array]))
449 return ENXIO;
450 if (rdp->flags & AR_F_REBUILDING)
451 return EBUSY;
452 /* create process here XXX SOS */
453 return ar_rebuild(rdp);
456 static int
457 aropen(struct dev_open_args *ap)
459 struct ar_softc *rdp = ap->a_head.a_dev->si_drv1;
460 struct disklabel *dl;
462 dl = &rdp->disk.d_label;
463 bzero(dl, sizeof *dl);
464 dl->d_secsize = DEV_BSIZE;
465 dl->d_nsectors = rdp->sectors;
466 dl->d_ntracks = rdp->heads;
467 dl->d_ncylinders = rdp->cylinders;
468 dl->d_secpercyl = rdp->sectors * rdp->heads;
469 dl->d_secperunit = rdp->total_sectors;
470 return 0;
473 static int
474 arstrategy(struct dev_strategy_args *ap)
476 cdev_t dev = ap->a_head.a_dev;
477 struct bio *bio = ap->a_bio;
478 struct buf *bp = bio->bio_buf;
479 struct ar_softc *rdp = dev->si_drv1;
480 int blkno, count, chunk, lba, lbs, tmplba;
481 int orig_blkno;
482 int buf1_blkno;
483 int drv = 0, change = 0;
484 caddr_t data;
486 if (!(rdp->flags & AR_F_READY)) {
487 bp->b_flags |= B_ERROR;
488 bp->b_error = EIO;
489 biodone(bio);
490 return(0);
493 KKASSERT((bio->bio_offset & DEV_BMASK) == 0);
495 bp->b_resid = bp->b_bcount;
496 blkno = (int)(bio->bio_offset >> DEV_BSHIFT);
497 orig_blkno = blkno;
498 data = bp->b_data;
500 for (count = howmany(bp->b_bcount, DEV_BSIZE); count > 0;
501 count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) {
502 struct ar_buf *buf1, *buf2;
504 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
505 case AR_F_SPAN:
506 lba = blkno;
507 while (lba >= AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved)
508 lba -= AD_SOFTC(rdp->disks[drv++])->total_secs-rdp->reserved;
509 chunk = min(AD_SOFTC(rdp->disks[drv])->total_secs-rdp->reserved-lba,
510 count);
511 break;
513 case AR_F_RAID0:
514 case AR_F_RAID0 | AR_F_RAID1:
515 tmplba = blkno / rdp->interleave;
516 chunk = blkno % rdp->interleave;
517 if (tmplba == rdp->total_sectors / rdp->interleave) {
518 lbs = (rdp->total_sectors-(tmplba*rdp->interleave))/rdp->width;
519 drv = chunk / lbs;
520 lba = ((tmplba/rdp->width)*rdp->interleave) + chunk%lbs;
521 chunk = min(count, lbs);
523 else {
524 drv = tmplba % rdp->width;
525 lba = ((tmplba / rdp->width) * rdp->interleave) + chunk;
526 chunk = min(count, rdp->interleave - chunk);
528 break;
530 case AR_F_RAID1:
531 drv = 0;
532 lba = blkno;
533 chunk = count;
534 break;
536 default:
537 kprintf("ar%d: unknown array type in arstrategy\n", rdp->lun);
538 bp->b_flags |= B_ERROR;
539 bp->b_error = EIO;
540 biodone(bio);
541 return(0);
544 buf1 = kmalloc(sizeof(struct ar_buf), M_AR, M_INTWAIT | M_ZERO);
545 BUF_LOCKINIT(&buf1->bp);
546 BUF_LOCK(&buf1->bp, LK_EXCLUSIVE);
547 initbufbio(&buf1->bp);
548 buf1->bp.b_bio1.bio_offset = (off_t)lba << DEV_BSHIFT;
549 if ((buf1->drive = drv) > 0)
550 buf1->bp.b_bio1.bio_offset += (off_t)rdp->offset << DEV_BSHIFT;
551 buf1->bp.b_bio1.bio_caller_info1.ptr = (void *)rdp;
552 buf1->bp.b_bcount = chunk * DEV_BSIZE;
553 buf1->bp.b_data = data;
554 buf1->bp.b_flags = bp->b_flags | B_PAGING;
555 buf1->bp.b_cmd = bp->b_cmd;
556 buf1->bp.b_bio1.bio_done = ar_done;
557 buf1->org = bio;
558 buf1_blkno = (int)(buf1->bp.b_bio1.bio_offset >> DEV_BSHIFT);
560 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
561 case AR_F_SPAN:
562 case AR_F_RAID0:
563 if ((rdp->disks[buf1->drive].flags &
564 (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
565 !AD_SOFTC(rdp->disks[buf1->drive])->dev) {
566 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
567 ar_config_changed(rdp, 1);
568 kfree(buf1, M_AR);
569 bp->b_flags |= B_ERROR;
570 bp->b_error = EIO;
571 biodone(bio);
572 return(0);
574 dev_dstrategy(AD_SOFTC(rdp->disks[buf1->drive])->dev,
575 &buf1->bp.b_bio1);
576 break;
578 case AR_F_RAID1:
579 case AR_F_RAID0 | AR_F_RAID1:
580 if ((rdp->flags & AR_F_REBUILDING) && bp->b_cmd != BUF_CMD_READ) {
581 if ((orig_blkno >= rdp->lock_start &&
582 orig_blkno < rdp->lock_end) ||
583 ((orig_blkno + chunk) > rdp->lock_start &&
584 (orig_blkno + chunk) <= rdp->lock_end)) {
585 tsleep(rdp, 0, "arwait", 0);
588 if ((rdp->disks[buf1->drive].flags &
589 (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
590 !AD_SOFTC(rdp->disks[buf1->drive])->dev) {
591 rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
592 change = 1;
594 if ((rdp->disks[buf1->drive + rdp->width].flags &
595 (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
596 !AD_SOFTC(rdp->disks[buf1->drive + rdp->width])->dev) {
597 rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE;
598 change = 1;
600 if (change)
601 ar_config_changed(rdp, 1);
603 if (!(rdp->flags & AR_F_READY)) {
604 kfree(buf1, M_AR);
605 bp->b_flags |= B_ERROR;
606 bp->b_error = EIO;
607 biodone(bio);
608 return(0);
610 if (bp->b_cmd == BUF_CMD_READ) {
611 if ((buf1_blkno <
612 (rdp->disks[buf1->drive].last_lba - AR_PROXIMITY) ||
613 buf1_blkno >
614 (rdp->disks[buf1->drive].last_lba + AR_PROXIMITY) ||
615 !(rdp->disks[buf1->drive].flags & AR_DF_ONLINE)) &&
616 (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE))
617 buf1->drive = buf1->drive + rdp->width;
618 } else {
619 if ((rdp->disks[buf1->drive+rdp->width].flags & AR_DF_ONLINE) ||
620 ((rdp->flags & AR_F_REBUILDING) &&
621 (rdp->disks[buf1->drive+rdp->width].flags & AR_DF_SPARE) &&
622 buf1_blkno < rdp->lock_start)) {
623 if ((rdp->disks[buf1->drive].flags & AR_DF_ONLINE) ||
624 ((rdp->flags & AR_F_REBUILDING) &&
625 (rdp->disks[buf1->drive].flags & AR_DF_SPARE) &&
626 buf1_blkno < rdp->lock_start)) {
627 buf2 = kmalloc(sizeof(struct ar_buf), M_AR, M_INTWAIT);
628 bcopy(buf1, buf2, sizeof(struct ar_buf));
629 BUF_LOCKINIT(&buf2->bp);
630 BUF_LOCK(&buf2->bp, LK_EXCLUSIVE);
631 initbufbio(&buf2->bp);
632 buf2->bp.b_bio1.bio_offset = buf1->bp.b_bio1.bio_offset;
633 buf1->mirror = buf2;
634 buf2->mirror = buf1;
635 buf2->drive = buf1->drive + rdp->width;
636 dev_dstrategy(AD_SOFTC(rdp->disks[buf2->drive])->dev,
637 &buf2->bp.b_bio1);
638 rdp->disks[buf2->drive].last_lba = buf1_blkno + chunk;
640 else
641 buf1->drive = buf1->drive + rdp->width;
644 dev_dstrategy(AD_SOFTC(rdp->disks[buf1->drive])->dev,
645 &buf1->bp.b_bio1);
646 rdp->disks[buf1->drive].last_lba = buf1_blkno + chunk;
647 break;
649 default:
650 kprintf("ar%d: unknown array type in arstrategy\n", rdp->lun);
653 return(0);
656 static void
657 ar_done(struct bio *bio)
659 struct ar_softc *rdp = (struct ar_softc *)bio->bio_caller_info1.ptr;
660 struct ar_buf *buf = (struct ar_buf *)bio->bio_buf;
662 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
663 case AR_F_SPAN:
664 case AR_F_RAID0:
665 if (buf->bp.b_flags & B_ERROR) {
666 rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
667 ar_config_changed(rdp, 1);
668 buf->org->bio_buf->b_flags |= B_ERROR;
669 buf->org->bio_buf->b_error = EIO;
670 biodone(buf->org);
672 else {
673 buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
674 if (buf->org->bio_buf->b_resid == 0)
675 biodone(buf->org);
677 break;
679 case AR_F_RAID1:
680 case AR_F_RAID0 | AR_F_RAID1:
681 if (buf->bp.b_flags & B_ERROR) {
682 rdp->disks[buf->drive].flags &= ~AR_DF_ONLINE;
683 ar_config_changed(rdp, 1);
684 if (rdp->flags & AR_F_READY) {
685 if (buf->bp.b_cmd == BUF_CMD_READ) {
686 if (buf->drive < rdp->width)
687 buf->drive = buf->drive + rdp->width;
688 else
689 buf->drive = buf->drive - rdp->width;
690 buf->bp.b_flags = buf->org->bio_buf->b_flags | B_PAGING;
691 buf->bp.b_error = 0;
692 dev_dstrategy(AD_SOFTC(rdp->disks[buf->drive])->dev,
693 &buf->bp.b_bio1);
694 return;
696 else {
697 if (buf->flags & AB_F_DONE) {
698 buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
699 if (buf->org->bio_buf->b_resid == 0)
700 biodone(buf->org);
702 else
703 buf->mirror->flags |= AB_F_DONE;
706 else {
707 buf->org->bio_buf->b_flags |= B_ERROR;
708 buf->org->bio_buf->b_error = EIO;
709 biodone(buf->org);
712 else {
713 if (buf->bp.b_cmd != BUF_CMD_READ) {
714 if (buf->mirror && !(buf->flags & AB_F_DONE)){
715 buf->mirror->flags |= AB_F_DONE;
716 break;
719 buf->org->bio_buf->b_resid -= buf->bp.b_bcount;
720 if (buf->org->bio_buf->b_resid == 0)
721 biodone(buf->org);
723 break;
725 default:
726 kprintf("ar%d: unknown array type in ar_done\n", rdp->lun);
728 kfree(buf, M_AR);
731 static void
732 ar_sync_done(struct bio *bio)
734 bio->bio_buf->b_cmd = BUF_CMD_DONE;
735 wakeup(bio);
738 static void
739 ar_config_changed(struct ar_softc *rdp, int writeback)
741 int disk, flags;
743 flags = rdp->flags;
744 rdp->flags |= AR_F_READY;
745 rdp->flags &= ~AR_F_DEGRADED;
747 for (disk = 0; disk < rdp->total_disks; disk++)
748 if (!(rdp->disks[disk].flags & AR_DF_PRESENT))
749 rdp->disks[disk].flags &= ~AR_DF_ONLINE;
751 for (disk = 0; disk < rdp->total_disks; disk++) {
752 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
753 case AR_F_SPAN:
754 case AR_F_RAID0:
755 if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) {
756 rdp->flags &= ~AR_F_READY;
757 kprintf("ar%d: ERROR - array broken\n", rdp->lun);
759 break;
761 case AR_F_RAID1:
762 case AR_F_RAID0 | AR_F_RAID1:
763 if (disk < rdp->width) {
764 if (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
765 !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) {
766 rdp->flags &= ~AR_F_READY;
767 kprintf("ar%d: ERROR - array broken\n", rdp->lun);
769 else if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
770 !(rdp->disks
771 [disk + rdp->width].flags & AR_DF_ONLINE))||
772 (!(rdp->disks[disk].flags & AR_DF_ONLINE) &&
773 (rdp->disks
774 [disk + rdp->width].flags & AR_DF_ONLINE))) {
775 rdp->flags |= AR_F_DEGRADED;
776 if (!(flags & AR_F_DEGRADED))
777 kprintf("ar%d: WARNING - mirror lost\n", rdp->lun);
780 break;
782 if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
783 if (rdp->disks[disk].flags & AR_DF_ONLINE)
784 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
785 else
786 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED);
789 if (writeback) {
790 if (rdp->flags & AR_F_PROMISE_RAID)
791 ar_promise_write_conf(rdp);
792 if (rdp->flags & AR_F_HIGHPOINT_RAID)
793 ar_highpoint_write_conf(rdp);
797 static int
798 ar_rebuild(struct ar_softc *rdp)
800 int disk, count = 0, error = 0;
801 caddr_t buffer;
803 if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED))
804 return EEXIST;
806 for (disk = 0; disk < rdp->total_disks; disk++) {
807 if (((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
808 (AR_DF_PRESENT | AR_DF_SPARE)) && rdp->disks[disk].device) {
809 if (AD_SOFTC(rdp->disks[disk])->total_secs <
810 rdp->disks[disk].disk_sectors) {
811 ata_prtdev(rdp->disks[disk].device,
812 "disk capacity too small for this RAID config\n");
813 #if 0
814 rdp->disks[disk].flags &= ~AR_DF_SPARE;
815 AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
816 #endif
817 continue;
819 ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE);
820 count++;
823 if (!count)
824 return ENODEV;
826 /* setup start conditions */
827 crit_enter();
828 rdp->lock_start = 0;
829 rdp->lock_end = rdp->lock_start + 256;
830 rdp->flags |= AR_F_REBUILDING;
831 crit_exit();
832 buffer = kmalloc(256 * DEV_BSIZE, M_AR, M_WAITOK | M_ZERO);
834 /* now go copy entire disk(s) */
835 while (rdp->lock_end < (rdp->total_sectors / rdp->width)) {
836 int size = min(256, (rdp->total_sectors / rdp->width) - rdp->lock_end);
838 for (disk = 0; disk < rdp->width; disk++) {
839 struct ad_softc *adp;
841 if (((rdp->disks[disk].flags & AR_DF_ONLINE) &&
842 (rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) ||
843 ((rdp->disks[disk].flags & AR_DF_ONLINE) &&
844 !(rdp->disks[disk + rdp->width].flags & AR_DF_SPARE)) ||
845 ((rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE) &&
846 !(rdp->disks[disk].flags & AR_DF_SPARE)))
847 continue;
849 if (rdp->disks[disk].flags & AR_DF_ONLINE)
850 adp = AD_SOFTC(rdp->disks[disk]);
851 else
852 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
853 if ((error = ar_rw(adp, rdp->lock_start,
854 size * DEV_BSIZE, buffer, AR_READ | AR_WAIT)))
855 break;
857 if (rdp->disks[disk].flags & AR_DF_ONLINE)
858 adp = AD_SOFTC(rdp->disks[disk + rdp->width]);
859 else
860 adp = AD_SOFTC(rdp->disks[disk]);
861 if ((error = ar_rw(adp, rdp->lock_start,
862 size * DEV_BSIZE, buffer, AR_WRITE | AR_WAIT)))
863 break;
865 if (error) {
866 wakeup(rdp);
867 kfree(buffer, M_AR);
868 return error;
870 crit_enter();
871 rdp->lock_start = rdp->lock_end;
872 rdp->lock_end = rdp->lock_start + size;
873 crit_exit();
874 wakeup(rdp);
876 kfree(buffer, M_AR);
877 for (disk = 0; disk < rdp->total_disks; disk++) {
878 if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
879 (AR_DF_PRESENT | AR_DF_SPARE)) {
880 rdp->disks[disk].flags &= ~AR_DF_SPARE;
881 rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE);
884 crit_enter();
885 rdp->lock_start = 0xffffffff;
886 rdp->lock_end = 0xffffffff;
887 rdp->flags &= ~AR_F_REBUILDING;
888 crit_exit();
889 ar_config_changed(rdp, 1);
890 return 0;
893 static int
894 ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp)
896 struct highpoint_raid_conf *info;
897 struct ar_softc *raid = NULL;
898 int array, disk_number = 0, retval = 0;
900 info = kmalloc(sizeof(struct highpoint_raid_conf), M_AR, M_INTWAIT|M_ZERO);
902 if (ar_rw(adp, HPT_LBA, sizeof(struct highpoint_raid_conf),
903 (caddr_t)info, AR_READ | AR_WAIT)) {
904 if (bootverbose)
905 kprintf("ar: HighPoint read conf failed\n");
906 goto highpoint_out;
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 kprintf("ar: HighPoint check1 failed\n");
913 goto highpoint_out;
916 /* is this disk defined, or an old leftover/spare ? */
917 if (!info->magic_0) {
918 if (bootverbose)
919 kprintf("ar: HighPoint check2 failed\n");
920 goto highpoint_out;
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] = kmalloc(sizeof(struct ar_softc), M_AR,
927 M_INTWAIT | M_ZERO);
929 raid = raidp[array];
930 if (raid->flags & AR_F_PROMISE_RAID)
931 continue;
933 switch (info->type) {
934 case HPT_T_RAID0:
935 if ((info->order & (HPT_O_RAID0|HPT_O_OK))==(HPT_O_RAID0|HPT_O_OK))
936 goto highpoint_raid1;
937 if (info->order & (HPT_O_RAID0 | HPT_O_RAID1))
938 goto highpoint_raid01;
939 if (raid->magic_0 && raid->magic_0 != info->magic_0)
940 continue;
941 raid->magic_0 = info->magic_0;
942 raid->flags |= AR_F_RAID0;
943 raid->interleave = 1 << info->stripe_shift;
944 disk_number = info->disk_number;
945 if (!(info->order & HPT_O_OK))
946 info->magic = 0; /* mark bad */
947 break;
949 case HPT_T_RAID1:
950 highpoint_raid1:
951 if (raid->magic_0 && raid->magic_0 != info->magic_0)
952 continue;
953 raid->magic_0 = info->magic_0;
954 raid->flags |= AR_F_RAID1;
955 disk_number = (info->disk_number > 0);
956 break;
958 case HPT_T_RAID01_RAID0:
959 highpoint_raid01:
960 if (info->order & HPT_O_RAID0) {
961 if ((raid->magic_0 && raid->magic_0 != info->magic_0) ||
962 (raid->magic_1 && raid->magic_1 != info->magic_1))
963 continue;
964 raid->magic_0 = info->magic_0;
965 raid->magic_1 = info->magic_1;
966 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
967 raid->interleave = 1 << info->stripe_shift;
968 disk_number = info->disk_number;
970 else {
971 if (raid->magic_1 && raid->magic_1 != info->magic_1)
972 continue;
973 raid->magic_1 = info->magic_1;
974 raid->flags |= (AR_F_RAID0 | AR_F_RAID1);
975 raid->interleave = 1 << info->stripe_shift;
976 disk_number = info->disk_number + info->array_width;
977 if (!(info->order & HPT_O_RAID1))
978 info->magic = 0; /* mark bad */
980 break;
982 case HPT_T_SPAN:
983 if (raid->magic_0 && raid->magic_0 != info->magic_0)
984 continue;
985 raid->magic_0 = info->magic_0;
986 raid->flags |= AR_F_SPAN;
987 disk_number = info->disk_number;
988 break;
990 default:
991 kprintf("ar%d: HighPoint unknown RAID type 0x%02x\n",
992 array, info->type);
993 goto highpoint_out;
996 raid->flags |= AR_F_HIGHPOINT_RAID;
997 raid->disks[disk_number].device = adp->device;
998 raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED);
999 raid->lun = array;
1000 if (info->magic == HPT_MAGIC_OK) {
1001 raid->disks[disk_number].flags |= AR_DF_ONLINE;
1002 raid->flags |= AR_F_READY;
1003 raid->width = info->array_width;
1004 raid->heads = 255;
1005 raid->sectors = 63;
1006 raid->cylinders = info->total_sectors / (63 * 255);
1007 raid->total_sectors = info->total_sectors;
1008 raid->offset = HPT_LBA + 1;
1009 raid->reserved = HPT_LBA + 1;
1010 raid->lock_start = raid->lock_end = info->rebuild_lba;
1011 raid->disks[disk_number].disk_sectors =
1012 info->total_sectors / info->array_width;
1014 else
1015 raid->disks[disk_number].flags &= ~ AR_DF_ONLINE;
1017 if ((raid->flags & AR_F_RAID0) && (raid->total_disks < raid->width))
1018 raid->total_disks = raid->width;
1019 if (disk_number >= raid->total_disks)
1020 raid->total_disks = disk_number + 1;
1021 retval = 1;
1022 break;
1024 highpoint_out:
1025 kfree(info, M_AR);
1026 return retval;
1029 static int
1030 ar_highpoint_write_conf(struct ar_softc *rdp)
1032 struct highpoint_raid_conf *config;
1033 struct timeval timestamp;
1034 int disk;
1036 microtime(&timestamp);
1037 rdp->magic_0 = timestamp.tv_sec + 2;
1038 rdp->magic_1 = timestamp.tv_sec;
1040 for (disk = 0; disk < rdp->total_disks; disk++) {
1041 config = kmalloc(sizeof(struct highpoint_raid_conf),
1042 M_AR, M_INTWAIT | M_ZERO);
1043 if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
1044 (AR_DF_PRESENT | AR_DF_ONLINE))
1045 config->magic = HPT_MAGIC_OK;
1046 if (rdp->disks[disk].flags & AR_DF_ASSIGNED) {
1047 config->magic_0 = rdp->magic_0;
1048 strcpy(config->name_1, "FreeBSD");
1050 config->disk_number = disk;
1052 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1053 case AR_F_RAID0:
1054 config->type = HPT_T_RAID0;
1055 strcpy(config->name_2, "RAID 0");
1056 if (rdp->disks[disk].flags & AR_DF_ONLINE)
1057 config->order = HPT_O_OK;
1058 break;
1060 case AR_F_RAID1:
1061 config->type = HPT_T_RAID0; /* bogus but old HPT BIOS need it */
1062 strcpy(config->name_2, "RAID 1");
1063 config->disk_number = (disk < rdp->width) ? disk : disk + 5;
1064 config->order = HPT_O_RAID0 | HPT_O_OK;
1065 break;
1067 case AR_F_RAID0 | AR_F_RAID1:
1068 config->type = HPT_T_RAID01_RAID0;
1069 strcpy(config->name_2, "RAID 0+1");
1070 if (rdp->disks[disk].flags & AR_DF_ONLINE) {
1071 if (disk < rdp->width) {
1072 config->order = (HPT_O_RAID0 | HPT_O_RAID1);
1073 config->magic_0 = rdp->magic_0 - 1;
1075 else {
1076 config->order = HPT_O_RAID1;
1077 config->disk_number -= rdp->width;
1080 else
1081 config->magic_0 = rdp->magic_0 - 1;
1082 config->magic_1 = rdp->magic_1;
1083 break;
1085 case AR_F_SPAN:
1086 config->type = HPT_T_SPAN;
1087 strcpy(config->name_2, "SPAN");
1088 break;
1091 config->array_width = rdp->width;
1092 config->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0;
1093 config->total_sectors = rdp->total_sectors;
1094 config->rebuild_lba = rdp->lock_start;
1096 if ((rdp->disks[disk].device && rdp->disks[disk].device->driver) &&
1097 !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1099 if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA,
1100 sizeof(struct highpoint_raid_conf),
1101 (caddr_t)config, AR_WRITE)) {
1102 kprintf("ar%d: Highpoint write conf failed\n", rdp->lun);
1103 return -1;
1107 return 0;
1110 static int
1111 ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
1113 struct promise_raid_conf *info;
1114 struct ar_softc *raid;
1115 u_int32_t magic, cksum, *ckptr;
1116 int array, count, disk, disksum = 0, retval = 0;
1118 info = kmalloc(sizeof(struct promise_raid_conf), M_AR, M_INTWAIT | M_ZERO);
1120 if (ar_rw(adp, PR_LBA(adp), sizeof(struct promise_raid_conf),
1121 (caddr_t)info, AR_READ | AR_WAIT)) {
1122 if (bootverbose)
1123 kprintf("ar: %s read conf failed\n", local ? "FreeBSD" : "Promise");
1124 goto promise_out;
1127 /* check if this is a Promise RAID struct (or our local one) */
1128 if (local) {
1129 if (strncmp(info->promise_id, ATA_MAGIC, sizeof(ATA_MAGIC))) {
1130 if (bootverbose)
1131 kprintf("ar: FreeBSD check1 failed\n");
1132 goto promise_out;
1135 else {
1136 if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) {
1137 if (bootverbose)
1138 kprintf("ar: Promise check1 failed\n");
1139 goto promise_out;
1143 /* check if the checksum is OK */
1144 for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++)
1145 cksum += *ckptr++;
1146 if (cksum != *ckptr) {
1147 if (bootverbose)
1148 kprintf("ar: %s check2 failed\n", local ? "FreeBSD" : "Promise");
1149 goto promise_out;
1152 /* now convert Promise config info into our generic form */
1153 if (info->raid.integrity != PR_I_VALID) {
1154 if (bootverbose)
1155 kprintf("ar: %s check3 failed\n", local ? "FreeBSD" : "Promise");
1156 goto promise_out;
1159 for (array = 0; array < MAX_ARRAYS; array++) {
1160 if (!raidp[array]) {
1161 raidp[array] = kmalloc(sizeof(struct ar_softc), M_AR,
1162 M_INTWAIT | M_ZERO);
1164 raid = raidp[array];
1165 if (raid->flags & AR_F_HIGHPOINT_RAID)
1166 continue;
1168 magic = (adp->device->channel->chiptype >> 16) |
1169 (info->raid.array_number << 16);
1171 if ((raid->flags & AR_F_PROMISE_RAID) && magic != raid->magic_0)
1172 continue;
1174 /* update our knowledge about the array config based on generation */
1175 if (!info->raid.generation || info->raid.generation > raid->generation){
1176 raid->generation = info->raid.generation;
1177 raid->flags = AR_F_PROMISE_RAID;
1178 if (local)
1179 raid->flags |= AR_F_FREEBSD_RAID;
1180 raid->magic_0 = magic;
1181 raid->lun = array;
1182 if ((info->raid.status &
1183 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) ==
1184 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) {
1185 raid->flags |= AR_F_READY;
1186 if (info->raid.status & PR_S_DEGRADED)
1187 raid->flags |= AR_F_DEGRADED;
1189 else
1190 raid->flags &= ~AR_F_READY;
1192 switch (info->raid.type) {
1193 case PR_T_RAID0:
1194 raid->flags |= AR_F_RAID0;
1195 break;
1197 case PR_T_RAID1:
1198 raid->flags |= AR_F_RAID1;
1199 if (info->raid.array_width > 1)
1200 raid->flags |= AR_F_RAID0;
1201 break;
1203 case PR_T_SPAN:
1204 raid->flags |= AR_F_SPAN;
1205 break;
1207 default:
1208 kprintf("ar%d: %s unknown RAID type 0x%02x\n",
1209 array, local ? "FreeBSD" : "Promise", info->raid.type);
1210 goto promise_out;
1212 raid->interleave = 1 << info->raid.stripe_shift;
1213 raid->width = info->raid.array_width;
1214 raid->total_disks = info->raid.total_disks;
1215 raid->heads = info->raid.heads + 1;
1216 raid->sectors = info->raid.sectors;
1217 raid->cylinders = info->raid.cylinders + 1;
1218 raid->total_sectors = info->raid.total_sectors;
1219 raid->offset = 0;
1220 raid->reserved = 63;
1221 raid->lock_start = raid->lock_end = info->raid.rebuild_lba;
1223 /* convert disk flags to our internal types */
1224 for (disk = 0; disk < info->raid.total_disks; disk++) {
1225 raid->disks[disk].flags = 0;
1226 disksum += info->raid.disk[disk].flags;
1227 if (info->raid.disk[disk].flags & PR_F_ONLINE)
1228 raid->disks[disk].flags |= AR_DF_ONLINE;
1229 if (info->raid.disk[disk].flags & PR_F_ASSIGNED)
1230 raid->disks[disk].flags |= AR_DF_ASSIGNED;
1231 if (info->raid.disk[disk].flags & PR_F_SPARE) {
1232 raid->disks[disk].flags &= ~AR_DF_ONLINE;
1233 raid->disks[disk].flags |= AR_DF_SPARE;
1235 if (info->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN))
1236 raid->disks[disk].flags &= ~AR_DF_ONLINE;
1238 if (!disksum) {
1239 kfree(raidp[array], M_AR);
1240 raidp[array] = NULL;
1241 goto promise_out;
1244 if (raid->disks[info->raid.disk_number].flags && adp->device) {
1245 raid->disks[info->raid.disk_number].device = adp->device;
1246 raid->disks[info->raid.disk_number].flags |= AR_DF_PRESENT;
1247 raid->disks[info->raid.disk_number].disk_sectors =
1248 info->raid.total_sectors / info->raid.array_width;
1249 /*info->raid.disk_sectors;*/
1250 retval = 1;
1252 break;
1254 promise_out:
1255 kfree(info, M_AR);
1256 return retval;
1259 static int
1260 ar_promise_write_conf(struct ar_softc *rdp)
1262 struct promise_raid_conf *config;
1263 struct timeval timestamp;
1264 u_int32_t *ckptr;
1265 int count, disk, drive;
1266 int local = rdp->flags & AR_F_FREEBSD_RAID;
1268 rdp->generation++;
1269 microtime(&timestamp);
1271 for (disk = 0; disk < rdp->total_disks; disk++) {
1272 config = kmalloc(sizeof(struct promise_raid_conf), M_AR, M_INTWAIT);
1273 for (count = 0; count < sizeof(struct promise_raid_conf); count++)
1274 *(((u_int8_t *)config) + count) = 255 - (count % 256);
1276 if (local)
1277 bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC));
1278 else
1279 bcopy(PR_MAGIC, config->promise_id, sizeof(PR_MAGIC));
1280 config->dummy_0 = 0x00020000;
1281 config->magic_0 = PR_MAGIC0(rdp->disks[disk]) | timestamp.tv_sec;
1282 config->magic_1 = timestamp.tv_sec >> 16;
1283 config->magic_2 = timestamp.tv_sec;
1284 config->raid.integrity = PR_I_VALID;
1286 config->raid.disk_number = disk;
1287 if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
1288 config->raid.channel = rdp->disks[disk].device->channel->unit;
1289 config->raid.device = (rdp->disks[disk].device->unit != 0);
1290 if (AD_SOFTC(rdp->disks[disk])->dev)
1291 config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk]));
1292 /*config->raid.disk_offset*/
1294 config->raid.magic_0 = config->magic_0;
1295 config->raid.rebuild_lba = rdp->lock_start;
1296 config->raid.generation = rdp->generation;
1298 if (rdp->flags & AR_F_READY) {
1299 config->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE);
1300 config->raid.status =
1301 (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY);
1302 if (rdp->flags & AR_F_DEGRADED)
1303 config->raid.status |= PR_S_DEGRADED;
1304 else
1305 config->raid.status |= PR_S_FUNCTIONAL;
1307 else {
1308 config->raid.status = 0;
1309 config->raid.flags = PR_F_DOWN;
1312 switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) {
1313 case AR_F_RAID0:
1314 config->raid.type = PR_T_RAID0;
1315 break;
1316 case AR_F_RAID1:
1317 config->raid.type = PR_T_RAID1;
1318 break;
1319 case AR_F_RAID0 | AR_F_RAID1:
1320 config->raid.type = PR_T_RAID1;
1321 break;
1322 case AR_F_SPAN:
1323 config->raid.type = PR_T_SPAN;
1324 break;
1327 config->raid.total_disks = rdp->total_disks;
1328 config->raid.stripe_shift = ffs(rdp->interleave) - 1;
1329 config->raid.array_width = rdp->width;
1330 config->raid.array_number = rdp->lun;
1331 config->raid.total_sectors = rdp->total_sectors;
1332 config->raid.cylinders = rdp->cylinders - 1;
1333 config->raid.heads = rdp->heads - 1;
1334 config->raid.sectors = rdp->sectors;
1335 config->raid.magic_1 = (u_int64_t)config->magic_2<<16 | config->magic_1;
1337 bzero(&config->raid.disk, 8 * 12);
1338 for (drive = 0; drive < rdp->total_disks; drive++) {
1339 config->raid.disk[drive].flags = 0;
1340 if (rdp->disks[drive].flags & AR_DF_PRESENT)
1341 config->raid.disk[drive].flags |= PR_F_VALID;
1342 if (rdp->disks[drive].flags & AR_DF_ASSIGNED)
1343 config->raid.disk[drive].flags |= PR_F_ASSIGNED;
1344 if (rdp->disks[drive].flags & AR_DF_ONLINE)
1345 config->raid.disk[drive].flags |= PR_F_ONLINE;
1346 else
1347 if (rdp->disks[drive].flags & AR_DF_PRESENT)
1348 config->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN);
1349 if (rdp->disks[drive].flags & AR_DF_SPARE)
1350 config->raid.disk[drive].flags |= PR_F_SPARE;
1351 config->raid.disk[drive].dummy_0 = 0x0;
1352 if (rdp->disks[drive].device) {
1353 config->raid.disk[drive].channel =
1354 rdp->disks[drive].device->channel->unit;
1355 config->raid.disk[drive].device =
1356 (rdp->disks[drive].device->unit != 0);
1358 config->raid.disk[drive].magic_0 =
1359 PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec;
1362 config->checksum = 0;
1363 for (ckptr = (int32_t *)config, count = 0; count < 511; count++)
1364 config->checksum += *ckptr++;
1365 if (rdp->disks[disk].device && rdp->disks[disk].device->driver &&
1366 !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
1367 if (ar_rw(AD_SOFTC(rdp->disks[disk]),
1368 PR_LBA(AD_SOFTC(rdp->disks[disk])),
1369 sizeof(struct promise_raid_conf),
1370 (caddr_t)config, AR_WRITE)) {
1371 kprintf("ar%d: %s write conf failed\n",
1372 rdp->lun, local ? "FreeBSD" : "Promise");
1373 return -1;
1377 return 0;
1380 static void
1381 ar_rw_done(struct bio *bio)
1383 struct buf *bp = bio->bio_buf;
1385 kfree(bp->b_data, M_AR);
1386 kfree(bp, M_AR);
1389 static int
1390 ar_rw(struct ad_softc *adp, u_int32_t lba, int count, caddr_t data, int flags)
1392 struct buf *bp;
1393 int retry = 0, error = 0;
1395 bp = kmalloc(sizeof(struct buf), M_AR, M_INTWAIT|M_ZERO);
1396 BUF_LOCKINIT(bp);
1397 BUF_LOCK(bp, LK_EXCLUSIVE);
1398 initbufbio(bp);
1399 bp->b_data = data;
1400 bp->b_bio1.bio_offset = (off_t)lba << DEV_BSHIFT;
1401 bp->b_bcount = count;
1402 if (flags & AR_WAIT)
1403 bp->b_bio1.bio_done = ar_sync_done;
1404 else
1405 bp->b_bio1.bio_done = ar_rw_done;
1406 if (flags & AR_READ)
1407 bp->b_cmd = BUF_CMD_READ;
1408 if (flags & AR_WRITE)
1409 bp->b_cmd = BUF_CMD_WRITE;
1410 KKASSERT(bp->b_cmd != BUF_CMD_DONE);
1412 dev_dstrategy(adp->dev, &bp->b_bio1);
1414 if (flags & AR_WAIT) {
1415 while ((retry++ < (15*hz/10)) && (error = !(bp->b_cmd == BUF_CMD_DONE)))
1416 error = tsleep(&bp->b_bio1, 0, "arrw", 10);
1417 if (!error && (bp->b_flags & B_ERROR))
1418 error = bp->b_error;
1419 kfree(bp, M_AR);
1421 return error;
1424 static struct ata_device *
1425 ar_locate_disk(int diskno)
1427 struct ata_channel *ch;
1428 int ctlr;
1430 for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
1431 if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
1432 continue;
1433 if (ch->devices & ATA_ATA_MASTER)
1434 if (ch->device[MASTER].driver &&
1435 ((struct ad_softc *)(ch->device[MASTER].driver))->lun == diskno)
1436 return &ch->device[MASTER];
1437 if (ch->devices & ATA_ATA_SLAVE)
1438 if (ch->device[SLAVE].driver &&
1439 ((struct ad_softc *)(ch->device[SLAVE].driver))->lun == diskno)
1440 return &ch->device[SLAVE];
1442 return NULL;