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