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