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