diff options
author | Søren Schmidt <sos@FreeBSD.org> | 2004-06-25 21:21:59 +0000 |
---|---|---|
committer | Søren Schmidt <sos@FreeBSD.org> | 2004-06-25 21:21:59 +0000 |
commit | dfc7e0081f58091dc7c0684572c6b9751fbf2089 (patch) | |
tree | 52119b01345e2e2304bca431b13d1c93dc956ca5 | |
parent | 1cf3fa793411dea41de7c0eba0076bf18690edf8 (diff) | |
download | src-test2-dfc7e0081f58091dc7c0684572c6b9751fbf2089.tar.gz src-test2-dfc7e0081f58091dc7c0684572c6b9751fbf2089.zip |
Notes
-rw-r--r-- | sys/dev/ata/ata-raid.c | 263 | ||||
-rw-r--r-- | sys/dev/ata/ata-raid.h | 101 |
2 files changed, 335 insertions, 29 deletions
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index be57886d5b9d..df28fdd7c16f 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -67,6 +67,8 @@ static void ar_config_changed(struct ar_softc *, int); static void ar_rebuild(void *); static int ar_highpoint_read_conf(struct ad_softc *, struct ar_softc **); static int ar_highpoint_write_conf(struct ar_softc *); +static int ar_lsi_read_conf(struct ad_softc *, struct ar_softc **); +static int ar_lsi_write_conf(struct ar_softc *); static int ar_promise_read_conf(struct ad_softc *, struct ar_softc **, int); static int ar_promise_write_conf(struct ar_softc *); static int ar_rw(struct ad_softc *, u_int32_t, int, caddr_t, int); @@ -121,6 +123,9 @@ ata_raiddisk_attach(struct ad_softc *adp) case ATA_HIGHPOINT_ID: return (ar_highpoint_read_conf(adp, ar_table)); + case ATA_SILICON_IMAGE_ID: + return (ar_lsi_read_conf(adp, ar_table)); + default: return (ar_promise_read_conf(adp, ar_table, 1)); } @@ -325,6 +330,12 @@ ata_raid_create(struct raid_setup *setup) AD_SOFTC(rdp->disks[disk])->total_secs; break; + case ATA_SILICON_IMAGE_ID: + ctlr |= AR_F_LSI_RAID; + rdp->disks[disk].disk_sectors = + AD_SOFTC(rdp->disks[disk])->total_secs - 4208; /* SOS */ + break; + default: ctlr |= AR_F_FREEBSD_RAID; /* FALLTHROUGH */ @@ -336,9 +347,12 @@ ata_raid_create(struct raid_setup *setup) break; } - if (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID) && - (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) != - (ctlr & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID))) { + if ((rdp->flags & + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) && + (rdp->flags & + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) != + (ctlr & + (AR_F_PROMISE_RAID | AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID))) { free(rdp, M_AR); return EXDEV; } @@ -397,10 +411,12 @@ ata_raid_create(struct raid_setup *setup) while (setup->interleave >>= 1) bit++; - if (rdp->flags & AR_F_PROMISE_RAID) - rdp->interleave = min(max(2, 1 << bit), 2048); if (rdp->flags & AR_F_HIGHPOINT_RAID) rdp->interleave = min(max(32, 1 << bit), 128); + if (rdp->flags & AR_F_LSI_RAID) + rdp->interleave = min(max(2, 1 << bit), 4096); + if (rdp->flags & AR_F_PROMISE_RAID) + rdp->interleave = min(max(2, 1 << bit), 2048); } rdp->total_disks = total_disks; rdp->width = total_disks / ((rdp->flags & AR_F_RAID1) ? 2 : 1); @@ -456,10 +472,14 @@ ata_raid_delete(int array) rdp->disks[disk].flags = 0; } } + + if (rdp->flags & AR_F_HIGHPOINT_RAID) + ar_highpoint_write_conf(rdp); + if (rdp->flags & AR_F_LSI_RAID) + ar_lsi_write_conf(rdp); if (rdp->flags & AR_F_PROMISE_RAID) ar_promise_write_conf(rdp); - else - ar_highpoint_write_conf(rdp); + disk_destroy(rdp->disk); free(rdp, M_AR); ar_table[array] = NULL; @@ -979,10 +999,12 @@ ar_config_changed(struct ar_softc *rdp, int writeback) } } if (writeback) { - if (rdp->flags & AR_F_PROMISE_RAID) - ar_promise_write_conf(rdp); if (rdp->flags & AR_F_HIGHPOINT_RAID) ar_highpoint_write_conf(rdp); + if (rdp->flags & AR_F_LSI_RAID) + ar_lsi_write_conf(rdp); + if (rdp->flags & AR_F_PROMISE_RAID) + ar_promise_write_conf(rdp); } } @@ -1134,7 +1156,7 @@ ar_highpoint_read_conf(struct ad_softc *adp, struct ar_softc **raidp) } } raid = raidp[array]; - if (raid->flags & AR_F_PROMISE_RAID) + if (raid->flags & (AR_F_PROMISE_RAID | AR_F_LSI_RAID)) continue; switch (info->type) { @@ -1197,6 +1219,8 @@ highpoint_raid01: default: printf("ar%d: HighPoint unknown RAID type 0x%02x\n", array, info->type); + free(raidp[array], M_AR); + raidp[array] = NULL; goto highpoint_out; } @@ -1229,6 +1253,7 @@ highpoint_raid01: retval = 1; break; } + highpoint_out: free(info, M_AR); return retval; @@ -1321,6 +1346,216 @@ ar_highpoint_write_conf(struct ar_softc *rdp) } static int +ar_lsi_read_conf(struct ad_softc *adp, struct ar_softc **raidp) +{ + struct lsi_raid_conf *info; + struct ar_softc *raid = NULL; + int array, retval = 0; + + if (!(info = (struct lsi_raid_conf *) + malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO))) + return retval; + + if (ar_rw(adp, LSI_LBA(adp), sizeof(struct lsi_raid_conf), + (caddr_t)info, AR_READ | AR_WAIT)) { + if (1 || bootverbose) + printf("ar: LSI read conf failed\n"); + goto lsi_out; + } + + /* check if this is a LSI RAID struct */ + if (strncmp(info->lsi_id, LSI_MAGIC, strlen(LSI_MAGIC))) { + if (1 || bootverbose) + printf("ar: LSI check1 failed\n"); + goto lsi_out; + } + + /* now convert LSI config info into our generic form */ + for (array = 0; array < MAX_ARRAYS; array++) { + int raid_entry, conf_entry; + + if (!raidp[array + info->raid_number]) { + raidp[array + info->raid_number] = + (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, + M_NOWAIT | M_ZERO); + if (!raidp[array + info->raid_number]) { + printf("ar%d: failed to allocate raid config storage\n", array); + goto lsi_out; + } + } + raid = raidp[array + info->raid_number]; + + if (raid->flags & (AR_F_PROMISE_RAID | AR_F_HIGHPOINT_RAID)) + continue; + + if (raid->magic_0 && + ((raid->magic_0 != info->timestamp) || + (raid->magic_1 != info->raid_number))) + continue; + + array += info->raid_number; + + raid_entry = info->raid_number; + conf_entry = (info->configs[raid_entry].raid.config_offset >> 4) + + info->disk_number - 1; + + switch (info->configs[raid_entry].raid.type) { + case LSI_R_RAID0: + raid->magic_0 = info->timestamp; + raid->magic_1 = info->raid_number; + raid->flags |= AR_F_RAID0; + raid->interleave = info->configs[raid_entry].raid.stripe_size; + raid->width = info->configs[raid_entry].raid.raid_width; + break; + + case LSI_R_RAID1: + raid->magic_0 = info->timestamp; + raid->magic_1 = info->raid_number; + raid->flags |= AR_F_RAID1; + raid->width = info->configs[raid_entry].raid.raid_width; + break; + + case LSI_R_RAID0 | LSI_R_RAID1: + raid->magic_0 = info->timestamp; + raid->magic_1 = info->raid_number; + raid->flags |= (AR_F_RAID0 | AR_F_RAID1); + raid->interleave = info->configs[raid_entry].raid.stripe_size; + raid->width = info->configs[raid_entry].raid.raid_width; + break; + + default: + printf("ar%d: LSI unknown RAID type 0x%02x\n", + array, info->configs[raid_entry].raid.type); + free(raidp[array], M_AR); + raidp[array] = NULL; + goto lsi_out; + } + + /* setup RAID specifics */ + raid->flags |= AR_F_LSI_RAID; + raid->generation = 0; + raid->total_disks = info->configs[raid_entry].raid.disk_count; + raid->heads = 255; + raid->sectors = 63; + raid->cylinders = info->configs[raid_entry].raid.total_sectors/(63*255); + raid->total_sectors = info->configs[raid_entry].raid.total_sectors; + raid->offset = 0; + raid->reserved = 1; + raid->lock_start = raid->lock_end = 0; + raid->lun = array; + + /* setup RAID specifics of this disk */ + if (info->configs[conf_entry].disk.device != LSI_D_NONE) { + raid->disks[info->disk_number].device = adp->device; + raid->disks[info->disk_number].disk_sectors = + info->configs[conf_entry].disk.disk_sectors; + raid->disks[info->disk_number].flags = + (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); + AD_SOFTC(raid->disks[info->disk_number])->flags |= + AD_F_RAID_SUBDISK; + retval = 1; + } + else + raid->disks[info->disk_number].flags &= ~AR_DF_ONLINE; + + return retval; + } + +lsi_out: + free(info, M_AR); + return retval; +} + +static int +ar_lsi_write_conf(struct ar_softc *rdp) +{ + struct lsi_raid_conf *config; + struct timeval timestamp; + int disk, disk_entry; + + microtime(×tamp); + rdp->magic_0 = timestamp.tv_sec & 0xffffffc0; + rdp->magic_1 = 0; + + for (disk = 0; disk < rdp->total_disks; disk++) { + if (!(config = (struct lsi_raid_conf *) + malloc(sizeof(struct lsi_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { + printf("ar%d: LSI write conf failed\n", rdp->lun); + return -1; + } + + bcopy(LSI_MAGIC, config->lsi_id, strlen(LSI_MAGIC)); + config->dummy_1 = 0x10; + config->flags = 0x19; /* SOS X */ + config->version[0] = '2'; + config->version[1] = '0'; + config->config_entries = 2 + rdp->total_disks; + config->raid_count = 1; + config->total_disks = rdp->total_disks; + config->dummy_e = 0xfc; + config->disk_number = disk; + config->raid_number = 0; + config->timestamp = rdp->magic_0; + + switch (rdp->flags & (AR_F_RAID0 | AR_F_RAID1 | AR_F_SPAN)) { + case AR_F_RAID0: + config->configs[0].raid.type = LSI_R_RAID0; + break; + + case AR_F_RAID1: + config->configs[0].raid.type = LSI_R_RAID1; + break; + + case AR_F_RAID0 | AR_F_RAID1: + config->flags = 0x15; /* SOS X */ + config->configs[0].raid.type = (LSI_R_RAID0 | LSI_R_RAID1); + break; + + default: + return -1; + } + + config->configs[0].raid.dummy_1 = 0x10; + config->configs[0].raid.stripe_size = rdp->interleave; + config->configs[0].raid.raid_width = rdp->width; + config->configs[0].raid.disk_count = rdp->total_disks; + config->configs[0].raid.config_offset = 2 * 0x10; + config->configs[0].raid.total_sectors = rdp->total_sectors; + + for (disk_entry = 0; disk_entry < rdp->total_disks; disk_entry++) { + if (rdp->disks[disk_entry].flags & AR_DF_ONLINE) + config->configs[1 + disk_entry].disk.device = + (rdp->disks[disk_entry].device->channel->unit ? + LSI_D_CHANNEL1 : LSI_D_CHANNEL0) | + (rdp->disks[disk_entry].device->unit ? + LSI_D_SLAVE : LSI_D_MASTER); + else { + config->configs[1 + disk_entry].disk.device = LSI_D_NONE; + config->configs[1 + disk_entry].disk.flags = LSI_D_GONE; + } + config->configs[1 + disk_entry].disk.dummy_1 = 0x10; + config->configs[1 + disk_entry].disk.disk_sectors = + rdp->disks[disk_entry].disk_sectors; + config->configs[1 + disk_entry].disk.disk_number = disk_entry; + config->configs[1 + disk_entry].disk.raid_number = 0; + } + + if ((rdp->disks[disk].device && rdp->disks[disk].device->softc) && + !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { + + if (ar_rw(AD_SOFTC(rdp->disks[disk]), + LSI_LBA(AD_SOFTC(rdp->disks[disk])), + sizeof(struct lsi_raid_conf), + (caddr_t)config, AR_WRITE)) { + printf("ar%d: LSI write conf failed\n", rdp->lun); + return -1; + } + } + } + return 0; +} + +static int ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) { struct promise_raid_conf *info; @@ -1341,14 +1576,14 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) /* check if this is a Promise RAID struct (or our local one) */ if (local) { - if (strncmp(info->promise_id, ATA_MAGIC, sizeof(ATA_MAGIC))) { + if (strncmp(info->promise_id, ATA_MAGIC, strlen(ATA_MAGIC))) { if (bootverbose) printf("ar: FreeBSD check1 failed\n"); goto promise_out; } } else { - if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) { + if (strncmp(info->promise_id, PR_MAGIC, strlen(PR_MAGIC))) { if (bootverbose) printf("ar: Promise check1 failed\n"); goto promise_out; @@ -1382,7 +1617,7 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) } } raid = raidp[array]; - if (raid->flags & AR_F_HIGHPOINT_RAID) + if (raid->flags & (AR_F_LSI_RAID | AR_F_HIGHPOINT_RAID)) continue; magic = (pci_get_device(device_get_parent( @@ -1428,6 +1663,8 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) default: printf("ar%d: %s unknown RAID type 0x%02x\n", array, local ? "FreeBSD" : "Promise", info->raid.type); + free(raidp[array], M_AR); + raidp[array] = NULL; goto promise_out; } raid->interleave = 1 << info->raid.stripe_shift; diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 9c71fa3cb5e4..7a3e7a998d58 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -55,17 +55,25 @@ struct ar_softc { int32_t magic_0; /* ident for this array */ int32_t magic_1; /* ident for this array */ int flags; -#define AR_F_RAID0 0x0001 /* STRIPE */ -#define AR_F_RAID1 0x0002 /* MIRROR */ -#define AR_F_SPAN 0x0004 /* SPAN */ -#define AR_F_READY 0x0100 -#define AR_F_DEGRADED 0x0200 -#define AR_F_REBUILDING 0x0400 -#define AR_F_PROMISE_RAID 0x1000 -#define AR_F_HIGHPOINT_RAID 0x2000 -#define AR_F_FREEBSD_RAID 0x4000 -#define AR_F_TOGGLE 0x8000 - +#define AR_F_SPAN 0x00000001 +#define AR_F_RAID0 0x00000002 +#define AR_F_RAID1 0x00000004 +#define AR_F_RAID3 0x00000008 +#define AR_F_RAID5 0x00000010 + +#define AR_F_READY 0x00000100 +#define AR_F_DEGRADED 0x00000200 +#define AR_F_REBUILDING 0x00000400 +#define AR_F_TOGGLE 0x00000800 + +#define AR_F_FREEBSD_RAID 0x00010000 +#define AR_F_PROMISE_RAID 0x00020000 +#define AR_F_HIGHPOINT_RAID 0x00040000 +#define AR_F_ADAPTEC_RAID 0x00080000 +#define AR_F_LSI_RAID 0x00100000 +#define AR_F_INTEL_RAID 0x00200000 +#define AR_F_QTEC_RAID 0x00400000 + int total_disks; /* number of disks in this array */ int generation; /* generation of this array */ struct ar_disk disks[MAX_DISKS+1]; /* ptr to each disk in array */ @@ -92,11 +100,12 @@ struct ar_buf { #define AB_F_DONE 0x01 }; + #define HPT_LBA 9 struct highpoint_raid_conf { int8_t filler1[32]; - u_int32_t magic; /* 0x20 */ + u_int32_t magic; #define HPT_MAGIC_OK 0x5a7816f0 #define HPT_MAGIC_BAD 0x5a7816fd @@ -148,6 +157,66 @@ struct highpoint_raid_conf { } __packed; +#define LSI_LBA(adp) (adp->total_secs - 1) + +struct lsi_raid_conf { + u_int8_t lsi_id[6]; +#define LSI_MAGIC "$XIDE$" + + u_int8_t dummy_1; + u_int8_t flags; + u_int8_t version[2]; + u_int8_t config_entries; + u_int8_t raid_count; + u_int8_t total_disks; + u_int8_t dummy_d; + u_int8_t dummy_e; + u_int8_t dummy_f; + + union { + struct { + u_int8_t type; +#define LSI_R_RAID0 0x01 +#define LSI_R_RAID1 0x02 +#define LSI_R_SPARE 0x08 + + u_int8_t dummy_1; + u_int16_t stripe_size; + u_int8_t raid_width; + u_int8_t disk_count; + u_int8_t config_offset; + u_int8_t dummy_7; + u_int8_t flags; +#define LSI_R_DEGRADED 0x02 + + u_int32_t total_sectors; + u_int8_t filler[3]; + } __packed raid; + struct { + u_int8_t device; +#define LSI_D_MASTER 0x00 +#define LSI_D_SLAVE 0x01 +#define LSI_D_CHANNEL0 0x00 +#define LSI_D_CHANNEL1 0x10 +#define LSI_D_NONE 0xff + + u_int8_t dummy_1; + u_int32_t disk_sectors; + u_int8_t disk_number; + u_int8_t raid_number; + u_int8_t flags; +#define LSI_D_GONE 0x02 + + u_int8_t filler[7]; + } __packed disk; + } configs[30]; + u_int8_t disk_number; + u_int8_t raid_number; + u_int32_t timestamp; + u_int8_t filler[10]; +} __packed; + + #define PR_LBA(adp) \ (((adp->total_secs / (adp->heads * adp->sectors)) * \ adp->heads * adp->sectors) - adp->sectors) @@ -164,7 +233,7 @@ struct promise_raid_conf { u_int32_t magic_2; u_int8_t filler1[470]; struct { - u_int32_t integrity; /* 0x200 */ + u_int32_t integrity; #define PR_I_VALID 0x00000080 u_int8_t flags; @@ -181,7 +250,7 @@ struct promise_raid_conf { u_int8_t channel; u_int8_t device; u_int64_t magic_0 __packed; - u_int32_t disk_offset; /* 0x210 */ + u_int32_t disk_offset; u_int32_t disk_sectors; u_int32_t rebuild_lba; u_int16_t generation; @@ -201,7 +270,7 @@ struct promise_raid_conf { #define PR_T_RAID5 0x04 #define PR_T_SPAN 0x08 - u_int8_t total_disks; /* 0x220 */ + u_int8_t total_disks; u_int8_t stripe_shift; u_int8_t array_width; u_int8_t array_number; @@ -210,7 +279,7 @@ struct promise_raid_conf { u_int8_t heads; u_int8_t sectors; int64_t magic_1 __packed; - struct { /* 0x240 */ + struct { u_int8_t flags; u_int8_t dummy_0; u_int8_t channel; |