--- src/sys/dev/ata/ata-raid.c 2007-08-13 22:46:31.000000000 +0400 +++ src/sys/dev/ata/ata-raid.c 2008-03-02 18:02:28.150645051 +0300 @@ -75,6 +75,9 @@ static int ata_raid_jmicron_read_meta(de static int ata_raid_jmicron_write_meta(struct ar_softc *rdp); static int ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp); static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp); +#if 0 +static int ata_raid_lsiv3_write_meta(struct ar_softc *rdp); +#endif static int ata_raid_nvidia_read_meta(device_t dev, struct ar_softc **raidp); static int ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native); static int ata_raid_promise_write_meta(struct ar_softc *rdp); @@ -1438,6 +1441,7 @@ ata_raid_write_metadata(struct ar_softc case AR_F_VIA_RAID: return ata_raid_via_write_meta(rdp); + #if 0 case AR_F_HPTV3_RAID: return ata_raid_hptv3_write_meta(rdp); @@ -2838,6 +2842,18 @@ lsiv2_out: free(meta, M_AR); return retval; } +static int +ata_raid_lsiv3_checksum(u_int8_t *begin, u_int8_t *end) +{ + u_int8_t checksum = 0; + + /* KASSERT(begin < end, ("invalid pointers")); */ + + while(begin < end) + checksum += *begin++; + + return (checksum); +} /* LSILogic V3 MegaRAID Metadata */ static int @@ -2847,8 +2863,8 @@ ata_raid_lsiv3_read_meta(device_t dev, s device_t parent = device_get_parent(dev); struct lsiv3_raid_conf *meta; struct ar_softc *raid = NULL; - u_int8_t checksum, *ptr; - int array, entry, count, disk_number, retval = 0; + u_int8_t checksum; + int array, entry, width, found, disk = 0, retval = 0; if (!(meta = (struct lsiv3_raid_conf *) malloc(sizeof(struct lsiv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) @@ -2868,9 +2884,17 @@ ata_raid_lsiv3_read_meta(device_t dev, s goto lsiv3_out; } - /* check if the checksum is OK */ - for (checksum = 0, ptr = meta->lsi_id, count = 0; count < 512; count++) - checksum += *ptr++; + /* check if the checksum_0 is OK */ + checksum = ata_raid_lsiv3_checksum((u_int8_t *)&meta->magic_0, + (u_int8_t *)&meta->filler_4[0]); + /* check if the checksum_1 is OK */ + if (!checksum) + checksum = ata_raid_lsiv3_checksum((u_int8_t *)&meta->lsi_id[0], + (u_int8_t *)&meta->filler_5); + /* check if the checksum_2 is OK */ + if (!checksum) + checksum = ata_raid_lsiv3_checksum((u_int8_t *)&meta->raid[0], + (u_int8_t *)&meta->checksum_2 + 1); if (checksum) { if (testing || bootverbose) device_printf(parent, "LSI (v3) check2 failed\n"); @@ -2881,7 +2905,7 @@ ata_raid_lsiv3_read_meta(device_t dev, s ata_raid_lsiv3_print_meta(meta); /* now convert LSI (v3) config meta into our generic form */ - for (array = 0, entry = 0; array < MAX_ARRAYS && entry < 8;) { + for (array = 0, entry = 0; array < MAX_ARRAYS && entry < 4;) { if (!raidp[array]) { raidp[array] = (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, @@ -2903,29 +2927,33 @@ ata_raid_lsiv3_read_meta(device_t dev, s continue; } - switch (meta->raid[entry].total_disks) { - case 0: + if (meta->raid[entry].total_disks == 0 || + meta->raid[entry].array_width < 1) { entry++; continue; - case 1: - if (meta->raid[entry].device == meta->device) { - disk_number = 0; + } + + for (width = 0, found = 0; width < meta->raid[entry].array_width && + width < 2; width++) { + for (disk = 0; disk < meta->raid[entry].total_disks && + disk < 4; disk++) + if (meta->device == meta->raid[entry].array[width].devices[disk]) { + found = 1; break; } + if (found) + break; + } + + if (!found) { if (raid->format) array++; entry++; continue; - case 2: - disk_number = (meta->device & (LSIV3_D_DEVICE|LSIV3_D_CHANNEL))?1:0; - break; - default: - device_printf(parent, "lsiv3 > 2 disk support untested!!\n"); - disk_number = (meta->device & LSIV3_D_DEVICE ? 1 : 0) + - (meta->device & LSIV3_D_CHANNEL ? 2 : 0); - break; } + raid->total_disks = meta->raid[entry].total_disks; + switch (meta->raid[entry].type) { case LSIV3_T_RAID0: raid->type = AR_T_RAID0; @@ -2933,8 +2961,13 @@ ata_raid_lsiv3_read_meta(device_t dev, s break; case LSIV3_T_RAID1: - raid->type = AR_T_RAID1; raid->width = meta->raid[entry].array_width; + if (raid->width > 1) { + raid->type = AR_T_RAID01; + raid->total_disks *= raid->width; + disk += width * raid->width; + } else + raid->type = AR_T_RAID1; break; default: @@ -2950,21 +2983,23 @@ ata_raid_lsiv3_read_meta(device_t dev, s raid->format = AR_F_LSIV3_RAID; raid->generation = 0; raid->interleave = meta->raid[entry].stripe_pages * 8; - raid->total_disks = meta->raid[entry].total_disks; - raid->total_sectors = raid->width * meta->raid[entry].sectors; + raid->total_sectors = raid->width * meta->raid[entry].array[width].sectors; raid->heads = 255; raid->sectors = 63; raid->cylinders = raid->total_sectors / (63 * 255); - raid->offset_sectors = meta->raid[entry].offset; + raid->offset_sectors = meta->raid[entry].array[width].offset; raid->rebuild_lba = 0; raid->lun = array; + raid->status = AR_S_READY; + if (meta->raid[entry].status & LSIV3_R_DEGRADED) + raid->status |= AR_S_DEGRADED; - raid->disks[disk_number].dev = parent; - raid->disks[disk_number].sectors = raid->total_sectors / raid->width; - raid->disks[disk_number].flags = + raid->disks[disk].dev = parent; + raid->disks[disk].sectors = raid->total_sectors / raid->width; + raid->disks[disk].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); ars->raid[raid->volume] = raid; - ars->disk_number[raid->volume] = disk_number; + ars->disk_number[raid->volume] = disk; retval = 1; entry++; array++; @@ -2972,8 +3007,102 @@ ata_raid_lsiv3_read_meta(device_t dev, s lsiv3_out: free(meta, M_AR); - return retval; + return (retval); +} + +#if 0 +static int +ata_raid_lsiv3_write_meta(struct ar_softc *rdp) +{ + struct lsiv3_raid_conf *meta; + struct timeval timestamp; + struct ar_softc *raid[2] = {rdp, NULL}; + struct ata_channel *ch; + struct ata_pci_controller *ctlr; + int i, j, array, disk, count, error = 0; + + if (!(meta = (struct lsiv3_raid_conf *) + malloc(sizeof(struct lsiv3_raid_conf), M_AR, M_NOWAIT))) { + printf("ar%d: failed to allocate metadata storage\n", rdp->lun); + return (ENOMEM); + } + + microtime(×tamp); + + /* how many arrays we have? One or two? */ + for (array = 0, count = 0; array < MAX_ARRAYS; array++) + if (ata_raid_arrays[array] != NULL && + ata_raid_arrays[array]->format == AR_F_LSIV3_RAID && + ata_raid_arrays[array]->magic_0 == rdp->magic_0) + { + count++; + if (ata_raid_array[array] != rdp) + raid[1] = ata_raid_array[array]; + } + + if (count > 2) { + printf("ar%d: lsiv3_write_meta: Too many arrays (%d)!", + rdp->lun, count); + free(meta, M_AR); + return (EIO); + } + + meta->magic_0 = 0xe2605000; + strncpy(meta->magic_1, "SATA", sizeof(meta->magic_1)); + for (i = 0; i < 4; i++) + meta->dummy_0[i].magic_0 = 0x0e000002; + strncpy(meta->magic_2, "$_ENQ$", sizeof(meta->magic_2)); + meta->magic_3 = 0x3133; + meta->checksum_0 = ata_raid_lsiv3_checksum((u_int8_t *)&meta->magic_0, + (u_int8_t *)&meta->filler_4[0]); + strncpy(meta->lsi_id, "$_IDE$", sizeof(meta->lsi_id)); + meta->magic_4 = 0x3133; + meta->raid_cnt = count; + meta->dummy_1 = 0x4008; + meta->checksum_1 = ata_raid_lsiv3_checksum((u_int8_t *)&meta->lsi_id[0], + (u_int8_t *)&meta->filler_5); + /* raid */ + for (i = 0; i < count; i++) { + meta->raid[i].stripe_pages = raid[i].interleave / 8; + if (raid[i].status & AR_S_DEGRADED) + meta->raid[i].status = LSIV3_R_DEGRADED; + meta->raid[i].array_width = 1; + switch (raid[i].type) { + case AR_T_RAID0: + meta->raid[i].type = LSIV3_T_RAID0; + meta->raid[i].total_disks = raid[i].width; + if (raid[i].status & AR_S_DEGRADED) + meta->raid[i].status = LSIV3_R_OFFLINE; + break; + case AR_T_RAID1: + meta->raid[i].type = LSIV3_T_RAID1; + meta->raid[i].total_disks = raid[i].total_disks; + break; + case AR_T_RAID01: + meta->raid[i].type = LSIV3_T_RAID1; + meta->raid[i].total_disks = raid[i].total_disks / 2; + meta->raid[i].array_width = raid[i].width; + }; + /* raid/array */ + for (j = 0; j < 2 && j < raid[i].width; j++) { + meta->raid[i].array[j].sectors = raid[i].total_sectors / raid[i].width; + meta->raid[i].array[j].offset = raid[i].offset_sectors; + + /* raid/array/disk */ + for (disk = 0; disk < meta->raid[i].total_disks && disk < 4; disk++) { + if (!raid[i].disks[disk + 2*j].dev) + continue; + ch = device_get_softc(device_get_parent( + raid[i].disks[disk + 2*j].dev)); + meta->raid[i].array[j].devices[disk] = + (ch->unit % 2) << 4 + ch->unit / 2; + } + } + } + + return (error); } +#endif /* nVidia MediaShield Metadata */ static int @@ -4734,44 +4863,80 @@ ata_raid_lsiv3_type(int type) } } +static char * +ata_raid_lsiv3_status(int type) +{ + static char buffer[16]; + + switch (type) { + case LSIV3_R_READY: return "READY"; + case LSIV3_R_DEGRADED: return "DEGRADED"; + case LSIV3_R_OFFLINE: return "OFFLINE"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} + +static char * +ata_raid_lsiv3_disk_status(int type) +{ + static char buffer[16]; + + switch (type) { + case LSIV3_D_ONLINE:return "ONLINE"; + case LSIV3_D_FAIL: return "FAIL"; + case LSIV3_D_CLEAR: return "CLEAR"; + default: sprintf(buffer, "UNKNOWN 0x%02x", type); + return buffer; + } +} static void ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta) { - int i; + int i, j, k; printf("******* ATA LSILogic V3 MegaRAID Metadata *******\n"); + printf("magic_0 0x%08x\n", meta->magic_0); + printf("dummy_0.magic_0 0x%08x\n", meta->dummy_0[0].magic_0); printf("lsi_id <%.6s>\n", meta->lsi_id); - printf("dummy_0 0x%04x\n", meta->dummy_0); - printf("version 0x%04x\n", meta->version); - printf("dummy_0 0x%04x\n", meta->dummy_1); + printf("dummy_1 0x%04x\n", meta->dummy_1); + printf("raid_cnt %d\n", meta->raid_cnt); printf("RAID configs:\n"); - for (i = 0; i < 8; i++) { + for (i = 0; i < meta->raid_cnt && i < 4; i++) { if (meta->raid[i].total_disks) { printf("%02d stripe_pages %u\n", i, meta->raid[i].stripe_pages); printf("%02d type %s\n", i, ata_raid_lsiv3_type(meta->raid[i].type)); + printf("%02d status %s\n", i, + ata_raid_lsiv3_status(meta->raid[i].status)); printf("%02d total_disks %u\n", i, meta->raid[i].total_disks); printf("%02d array_width %u\n", i, meta->raid[i].array_width); - printf("%02d sectors %u\n", i, meta->raid[i].sectors); - printf("%02d offset %u\n", i, meta->raid[i].offset); - printf("%02d device 0x%02x\n", i, - meta->raid[i].device); + for (j = 0; j < 2 && j < meta->raid[i].array_width; j++) { + printf("%02d:%02d sectors %u\n", i, j, + meta->raid[i].array[j].sectors); + printf("%02d:%02d offset %u\n", i, j, + meta->raid[i].array[j].offset); + printf("%02d:%02d devices ", i, j); + for(k = 0; k < 4 && k < meta->raid[i].total_disks; k++) + printf("0x%02x ", meta->raid[i].array[j].devices[k]); + printf("\n"); + } } } printf("DISK configs:\n"); - for (i = 0; i < 6; i++) { + for (i = 0; i < 4; i++) { if (meta->disk[i].disk_sectors) { printf("%02d disk_sectors %u\n", i, meta->disk[i].disk_sectors); - printf("%02d flags 0x%02x\n", i, meta->disk[i].flags); + printf("%02d disk_status %s\n", i, + ata_raid_lsiv3_disk_status(meta->disk[i].disk_status)); } } printf("device 0x%02x\n", meta->device); printf("timestamp 0x%08x\n", meta->timestamp); - printf("checksum_1 0x%02x\n", meta->checksum_1); printf("=================================================\n"); } --- src/sys/dev/ata/ata-raid.h 2007-02-21 22:07:18.000000000 +0300 +++ src/sys/dev/ata/ata-raid.h 2008-03-01 14:43:14.365998728 +0300 @@ -509,25 +509,29 @@ struct lsiv2_raid_conf { (((struct ad_softc *)device_get_ivars(dev))->total_secs - 4) struct lsiv3_raid_conf { - u_int32_t magic_0; /* 0xa0203200 */ + u_int32_t magic_0; /* 0xe2605000 */ u_int32_t filler_0[3]; u_int8_t magic_1[4]; /* "SATA" */ u_int32_t filler_1[40]; - u_int32_t dummy_0; /* 0x0d000003 */ - u_int32_t filler_2[7]; - u_int32_t dummy_1; /* 0x0d000003 */ - u_int32_t filler_3[70]; - u_int8_t magic_2[8]; /* "$_ENQ$31" */ - u_int8_t filler_4[7]; - u_int8_t checksum_0; - u_int8_t filler_5[512*2]; + + struct { + u_int32_t magic_0; /* 0xe0000002 */ + u_int32_t filler_0[3]; + } __packed dummy_0[4]; + + u_int32_t filler_2[63]; + u_int8_t magic_2[6]; /* "$_ENQ$" */ + u_int8_t checksum_0; /* magic_0 .. filler_4 */ + u_int16_t magic_3; /* 0x3133 */ + u_int8_t filler_4[1031]; u_int8_t lsi_id[6]; #define LSIV3_MAGIC "$_IDE$" - u_int16_t dummy_2; /* 0x33de for OK disk */ - u_int16_t version; /* 0x0131 for this version */ - u_int16_t dummy_3; /* 0x0440 always */ - u_int32_t filler_6; + u_int8_t checksum_1; /* lsi_id .. filler5 */ + u_int16_t magic_4; /* 0x3133 */ + u_int8_t raid_cnt; + u_int16_t dummy_1; /* 0x4008 */ + u_int32_t filler_5; struct { u_int16_t stripe_pages; @@ -535,40 +539,39 @@ struct lsiv3_raid_conf { #define LSIV3_T_RAID0 0x00 #define LSIV3_T_RAID1 0x01 - u_int8_t dummy_0; + u_int8_t status; +#define LSIV3_R_READY 0x00 +#define LSIV3_R_DEGRADED 0x02 +#define LSIV3_R_OFFLINE 0x03 + u_int8_t total_disks; u_int8_t array_width; u_int8_t filler_0[10]; + struct { u_int32_t sectors; u_int16_t dummy_1; u_int32_t offset; u_int16_t dummy_2; - u_int8_t device; -#define LSIV3_D_DEVICE 0x01 -#define LSIV3_D_CHANNEL 0x10 - - u_int8_t dummy_3; - u_int8_t dummy_4; - u_int8_t dummy_5; - u_int8_t filler_1[16]; + u_int8_t devices[4]; + } __packed array[2]; } __packed raid[8]; + struct { u_int32_t disk_sectors; - u_int32_t dummy_0; - u_int32_t dummy_1; - u_int8_t dummy_2; - u_int8_t dummy_3; - u_int8_t flags; -#define LSIV3_D_MIRROR 0x00 -#define LSIV3_D_STRIPE 0xff - u_int8_t dummy_4; - } __packed disk[6]; - u_int8_t filler_7[7]; + u_int16_t dummy_0; + u_int8_t disk_status; +#define LSIV3_D_ONLINE 0x00 +#define LSIV3_D_FAIL 0x02 +#define LSIV3_D_CLEAR 0xff + + u_int8_t dummy_1; + } __packed disk[8]; + u_int8_t filler_6[39]; u_int8_t device; u_int32_t timestamp; - u_int8_t filler_8[3]; - u_int8_t checksum_1; + u_int8_t filler_7[3]; + u_int8_t checksum_2; } __packed;