100f32ecbSAlexander Motin /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
400f32ecbSAlexander Motin * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
500f32ecbSAlexander Motin * All rights reserved.
600f32ecbSAlexander Motin *
700f32ecbSAlexander Motin * Redistribution and use in source and binary forms, with or without
800f32ecbSAlexander Motin * modification, are permitted provided that the following conditions
900f32ecbSAlexander Motin * are met:
1000f32ecbSAlexander Motin * 1. Redistributions of source code must retain the above copyright
1100f32ecbSAlexander Motin * notice, this list of conditions and the following disclaimer.
1200f32ecbSAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright
1300f32ecbSAlexander Motin * notice, this list of conditions and the following disclaimer in the
1400f32ecbSAlexander Motin * documentation and/or other materials provided with the distribution.
1500f32ecbSAlexander Motin *
1600f32ecbSAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1700f32ecbSAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1800f32ecbSAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1900f32ecbSAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2000f32ecbSAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2100f32ecbSAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2200f32ecbSAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2300f32ecbSAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2400f32ecbSAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2500f32ecbSAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2600f32ecbSAlexander Motin * SUCH DAMAGE.
2700f32ecbSAlexander Motin */
2800f32ecbSAlexander Motin
2900f32ecbSAlexander Motin #include <sys/param.h>
3000f32ecbSAlexander Motin #include <sys/bio.h>
31f89d2072SXin LI #include <sys/gsb_crc32.h>
3200f32ecbSAlexander Motin #include <sys/endian.h>
3300f32ecbSAlexander Motin #include <sys/kernel.h>
3400f32ecbSAlexander Motin #include <sys/kobj.h>
3500f32ecbSAlexander Motin #include <sys/limits.h>
3600f32ecbSAlexander Motin #include <sys/lock.h>
3700f32ecbSAlexander Motin #include <sys/malloc.h>
3800f32ecbSAlexander Motin #include <sys/mutex.h>
3900f32ecbSAlexander Motin #include <sys/systm.h>
4000f32ecbSAlexander Motin #include <sys/time.h>
4100f32ecbSAlexander Motin #include <sys/clock.h>
422c385d51SSean Bruno #include <sys/disk.h>
4300f32ecbSAlexander Motin #include <geom/geom.h>
44ac03832eSConrad Meyer #include <geom/geom_dbg.h>
4500f32ecbSAlexander Motin #include "geom/raid/g_raid.h"
4600f32ecbSAlexander Motin #include "geom/raid/md_ddf.h"
4700f32ecbSAlexander Motin #include "g_raid_md_if.h"
4800f32ecbSAlexander Motin
4900f32ecbSAlexander Motin static MALLOC_DEFINE(M_MD_DDF, "md_ddf_data", "GEOM_RAID DDF metadata");
5000f32ecbSAlexander Motin
5100f32ecbSAlexander Motin #define DDF_MAX_DISKS_HARD 128
5200f32ecbSAlexander Motin
5300f32ecbSAlexander Motin #define DDF_MAX_DISKS 16
5400f32ecbSAlexander Motin #define DDF_MAX_VDISKS 7
5500f32ecbSAlexander Motin #define DDF_MAX_PARTITIONS 1
5600f32ecbSAlexander Motin
5700f32ecbSAlexander Motin #define DECADE (3600*24*(365*10+2)) /* 10 years in seconds. */
5800f32ecbSAlexander Motin
5900f32ecbSAlexander Motin struct ddf_meta {
6000f32ecbSAlexander Motin u_int sectorsize;
6100f32ecbSAlexander Motin u_int bigendian;
6200f32ecbSAlexander Motin struct ddf_header *hdr;
6300f32ecbSAlexander Motin struct ddf_cd_record *cdr;
6400f32ecbSAlexander Motin struct ddf_pd_record *pdr;
6500f32ecbSAlexander Motin struct ddf_vd_record *vdr;
6600f32ecbSAlexander Motin void *cr;
6700f32ecbSAlexander Motin struct ddf_pdd_record *pdd;
6800f32ecbSAlexander Motin struct ddf_bbm_log *bbm;
6900f32ecbSAlexander Motin };
7000f32ecbSAlexander Motin
7100f32ecbSAlexander Motin struct ddf_vol_meta {
7200f32ecbSAlexander Motin u_int sectorsize;
7300f32ecbSAlexander Motin u_int bigendian;
7400f32ecbSAlexander Motin struct ddf_header *hdr;
7500f32ecbSAlexander Motin struct ddf_cd_record *cdr;
7600f32ecbSAlexander Motin struct ddf_vd_entry *vde;
7700f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
7800f32ecbSAlexander Motin struct ddf_vdc_record *bvdc[DDF_MAX_DISKS_HARD];
7900f32ecbSAlexander Motin };
8000f32ecbSAlexander Motin
8100f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk {
8200f32ecbSAlexander Motin struct ddf_meta pd_meta;
8300f32ecbSAlexander Motin };
8400f32ecbSAlexander Motin
8500f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume {
8600f32ecbSAlexander Motin struct ddf_vol_meta pv_meta;
8700f32ecbSAlexander Motin int pv_started;
8800f32ecbSAlexander Motin struct callout pv_start_co; /* STARTING state timer. */
8900f32ecbSAlexander Motin };
9000f32ecbSAlexander Motin
9100f32ecbSAlexander Motin struct g_raid_md_ddf_object {
9200f32ecbSAlexander Motin struct g_raid_md_object mdio_base;
938df8e26aSAlexander Motin u_int mdio_bigendian;
9400f32ecbSAlexander Motin struct ddf_meta mdio_meta;
9547e98096SAlexander Motin int mdio_starting;
9600f32ecbSAlexander Motin struct callout mdio_start_co; /* STARTING state timer. */
9700f32ecbSAlexander Motin int mdio_started;
9800f32ecbSAlexander Motin struct root_hold_token *mdio_rootmount; /* Root mount delay token. */
9900f32ecbSAlexander Motin };
10000f32ecbSAlexander Motin
1018df8e26aSAlexander Motin static g_raid_md_create_req_t g_raid_md_create_req_ddf;
10200f32ecbSAlexander Motin static g_raid_md_taste_t g_raid_md_taste_ddf;
10300f32ecbSAlexander Motin static g_raid_md_event_t g_raid_md_event_ddf;
10400f32ecbSAlexander Motin static g_raid_md_volume_event_t g_raid_md_volume_event_ddf;
10500f32ecbSAlexander Motin static g_raid_md_ctl_t g_raid_md_ctl_ddf;
10600f32ecbSAlexander Motin static g_raid_md_write_t g_raid_md_write_ddf;
10700f32ecbSAlexander Motin static g_raid_md_fail_disk_t g_raid_md_fail_disk_ddf;
10800f32ecbSAlexander Motin static g_raid_md_free_disk_t g_raid_md_free_disk_ddf;
10900f32ecbSAlexander Motin static g_raid_md_free_volume_t g_raid_md_free_volume_ddf;
11000f32ecbSAlexander Motin static g_raid_md_free_t g_raid_md_free_ddf;
11100f32ecbSAlexander Motin
11200f32ecbSAlexander Motin static kobj_method_t g_raid_md_ddf_methods[] = {
1138df8e26aSAlexander Motin KOBJMETHOD(g_raid_md_create_req, g_raid_md_create_req_ddf),
11400f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_ddf),
11500f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_event, g_raid_md_event_ddf),
11600f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_volume_event, g_raid_md_volume_event_ddf),
11700f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_ddf),
11800f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_write, g_raid_md_write_ddf),
11900f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_ddf),
12000f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_ddf),
12100f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_free_volume, g_raid_md_free_volume_ddf),
12200f32ecbSAlexander Motin KOBJMETHOD(g_raid_md_free, g_raid_md_free_ddf),
12300f32ecbSAlexander Motin { 0, 0 }
12400f32ecbSAlexander Motin };
12500f32ecbSAlexander Motin
12600f32ecbSAlexander Motin static struct g_raid_md_class g_raid_md_ddf_class = {
12700f32ecbSAlexander Motin "DDF",
12800f32ecbSAlexander Motin g_raid_md_ddf_methods,
12900f32ecbSAlexander Motin sizeof(struct g_raid_md_ddf_object),
130c89d2fbeSAlexander Motin .mdc_enable = 1,
13100f32ecbSAlexander Motin .mdc_priority = 100
13200f32ecbSAlexander Motin };
13300f32ecbSAlexander Motin
13400f32ecbSAlexander Motin #define GET8(m, f) ((m)->f)
13500f32ecbSAlexander Motin #define GET16(m, f) ((m)->bigendian ? be16dec(&(m)->f) : le16dec(&(m)->f))
13600f32ecbSAlexander Motin #define GET32(m, f) ((m)->bigendian ? be32dec(&(m)->f) : le32dec(&(m)->f))
13700f32ecbSAlexander Motin #define GET64(m, f) ((m)->bigendian ? be64dec(&(m)->f) : le64dec(&(m)->f))
13800f32ecbSAlexander Motin #define GET8D(m, f) (f)
13900f32ecbSAlexander Motin #define GET16D(m, f) ((m)->bigendian ? be16dec(&f) : le16dec(&f))
14000f32ecbSAlexander Motin #define GET32D(m, f) ((m)->bigendian ? be32dec(&f) : le32dec(&f))
14100f32ecbSAlexander Motin #define GET64D(m, f) ((m)->bigendian ? be64dec(&f) : le64dec(&f))
14200f32ecbSAlexander Motin #define GET8P(m, f) (*(f))
14300f32ecbSAlexander Motin #define GET16P(m, f) ((m)->bigendian ? be16dec(f) : le16dec(f))
14400f32ecbSAlexander Motin #define GET32P(m, f) ((m)->bigendian ? be32dec(f) : le32dec(f))
14500f32ecbSAlexander Motin #define GET64P(m, f) ((m)->bigendian ? be64dec(f) : le64dec(f))
14600f32ecbSAlexander Motin
14700f32ecbSAlexander Motin #define SET8P(m, f, v) \
14800f32ecbSAlexander Motin (*(f) = (v))
14900f32ecbSAlexander Motin #define SET16P(m, f, v) \
15000f32ecbSAlexander Motin do { \
15100f32ecbSAlexander Motin if ((m)->bigendian) \
15200f32ecbSAlexander Motin be16enc((f), (v)); \
15300f32ecbSAlexander Motin else \
15400f32ecbSAlexander Motin le16enc((f), (v)); \
15500f32ecbSAlexander Motin } while (0)
15600f32ecbSAlexander Motin #define SET32P(m, f, v) \
15700f32ecbSAlexander Motin do { \
15800f32ecbSAlexander Motin if ((m)->bigendian) \
15900f32ecbSAlexander Motin be32enc((f), (v)); \
16000f32ecbSAlexander Motin else \
16100f32ecbSAlexander Motin le32enc((f), (v)); \
16200f32ecbSAlexander Motin } while (0)
16300f32ecbSAlexander Motin #define SET64P(m, f, v) \
16400f32ecbSAlexander Motin do { \
16500f32ecbSAlexander Motin if ((m)->bigendian) \
16600f32ecbSAlexander Motin be64enc((f), (v)); \
16700f32ecbSAlexander Motin else \
16800f32ecbSAlexander Motin le64enc((f), (v)); \
16900f32ecbSAlexander Motin } while (0)
17000f32ecbSAlexander Motin #define SET8(m, f, v) SET8P((m), &((m)->f), (v))
17100f32ecbSAlexander Motin #define SET16(m, f, v) SET16P((m), &((m)->f), (v))
17200f32ecbSAlexander Motin #define SET32(m, f, v) SET32P((m), &((m)->f), (v))
17300f32ecbSAlexander Motin #define SET64(m, f, v) SET64P((m), &((m)->f), (v))
17400f32ecbSAlexander Motin #define SET8D(m, f, v) SET8P((m), &(f), (v))
17500f32ecbSAlexander Motin #define SET16D(m, f, v) SET16P((m), &(f), (v))
17600f32ecbSAlexander Motin #define SET32D(m, f, v) SET32P((m), &(f), (v))
17700f32ecbSAlexander Motin #define SET64D(m, f, v) SET64P((m), &(f), (v))
17800f32ecbSAlexander Motin
1792b9c925fSAlexander Motin #define GETCRNUM(m) (GET32((m), hdr->cr_length) / \
1802b9c925fSAlexander Motin GET16((m), hdr->Configuration_Record_Length))
1812b9c925fSAlexander Motin
1822b9c925fSAlexander Motin #define GETVDCPTR(m, n) ((struct ddf_vdc_record *)((uint8_t *)(m)->cr + \
1832b9c925fSAlexander Motin (n) * GET16((m), hdr->Configuration_Record_Length) * \
1842b9c925fSAlexander Motin (m)->sectorsize))
1852b9c925fSAlexander Motin
186d525d875SAlexander Motin #define GETSAPTR(m, n) ((struct ddf_sa_record *)((uint8_t *)(m)->cr + \
187d525d875SAlexander Motin (n) * GET16((m), hdr->Configuration_Record_Length) * \
188d525d875SAlexander Motin (m)->sectorsize))
189d525d875SAlexander Motin
19000f32ecbSAlexander Motin static int
isff(uint8_t * buf,int size)19100f32ecbSAlexander Motin isff(uint8_t *buf, int size)
19200f32ecbSAlexander Motin {
19300f32ecbSAlexander Motin int i;
19400f32ecbSAlexander Motin
19500f32ecbSAlexander Motin for (i = 0; i < size; i++)
19600f32ecbSAlexander Motin if (buf[i] != 0xff)
19700f32ecbSAlexander Motin return (0);
19800f32ecbSAlexander Motin return (1);
19900f32ecbSAlexander Motin }
20000f32ecbSAlexander Motin
20100f32ecbSAlexander Motin static void
print_guid(uint8_t * buf)20200f32ecbSAlexander Motin print_guid(uint8_t *buf)
20300f32ecbSAlexander Motin {
20400f32ecbSAlexander Motin int i, ascii;
20500f32ecbSAlexander Motin
20600f32ecbSAlexander Motin ascii = 1;
20700f32ecbSAlexander Motin for (i = 0; i < 24; i++) {
20800f32ecbSAlexander Motin if (buf[i] != 0 && (buf[i] < ' ' || buf[i] > 127)) {
20900f32ecbSAlexander Motin ascii = 0;
21000f32ecbSAlexander Motin break;
21100f32ecbSAlexander Motin }
21200f32ecbSAlexander Motin }
21300f32ecbSAlexander Motin if (ascii) {
21400f32ecbSAlexander Motin printf("'%.24s'", buf);
21500f32ecbSAlexander Motin } else {
21600f32ecbSAlexander Motin for (i = 0; i < 24; i++)
21700f32ecbSAlexander Motin printf("%02x", buf[i]);
21800f32ecbSAlexander Motin }
21900f32ecbSAlexander Motin }
22000f32ecbSAlexander Motin
22100f32ecbSAlexander Motin static void
g_raid_md_ddf_print(struct ddf_meta * meta)22200f32ecbSAlexander Motin g_raid_md_ddf_print(struct ddf_meta *meta)
22300f32ecbSAlexander Motin {
22400f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
22500f32ecbSAlexander Motin struct ddf_vuc_record *vuc;
22600f32ecbSAlexander Motin struct ddf_sa_record *sa;
22700f32ecbSAlexander Motin uint64_t *val2;
22800f32ecbSAlexander Motin uint32_t val;
22900f32ecbSAlexander Motin int i, j, k, num, num2;
23000f32ecbSAlexander Motin
23100f32ecbSAlexander Motin if (g_raid_debug < 1)
23200f32ecbSAlexander Motin return;
23300f32ecbSAlexander Motin
23400f32ecbSAlexander Motin printf("********* DDF Metadata *********\n");
23500f32ecbSAlexander Motin printf("**** Header ****\n");
23600f32ecbSAlexander Motin printf("DDF_Header_GUID ");
23700f32ecbSAlexander Motin print_guid(meta->hdr->DDF_Header_GUID);
23800f32ecbSAlexander Motin printf("\n");
23900f32ecbSAlexander Motin printf("DDF_rev %8.8s\n", (char *)&meta->hdr->DDF_rev[0]);
24000f32ecbSAlexander Motin printf("Sequence_Number 0x%08x\n", GET32(meta, hdr->Sequence_Number));
24100f32ecbSAlexander Motin printf("TimeStamp 0x%08x\n", GET32(meta, hdr->TimeStamp));
24200f32ecbSAlexander Motin printf("Open_Flag 0x%02x\n", GET16(meta, hdr->Open_Flag));
24300f32ecbSAlexander Motin printf("Foreign_Flag 0x%02x\n", GET16(meta, hdr->Foreign_Flag));
24400f32ecbSAlexander Motin printf("Diskgrouping 0x%02x\n", GET16(meta, hdr->Diskgrouping));
24500f32ecbSAlexander Motin printf("Primary_Header_LBA %ju\n", GET64(meta, hdr->Primary_Header_LBA));
24600f32ecbSAlexander Motin printf("Secondary_Header_LBA %ju\n", GET64(meta, hdr->Secondary_Header_LBA));
24700f32ecbSAlexander Motin printf("WorkSpace_Length %u\n", GET32(meta, hdr->WorkSpace_Length));
24800f32ecbSAlexander Motin printf("WorkSpace_LBA %ju\n", GET64(meta, hdr->WorkSpace_LBA));
24900f32ecbSAlexander Motin printf("Max_PD_Entries %u\n", GET16(meta, hdr->Max_PD_Entries));
25000f32ecbSAlexander Motin printf("Max_VD_Entries %u\n", GET16(meta, hdr->Max_VD_Entries));
25100f32ecbSAlexander Motin printf("Max_Partitions %u\n", GET16(meta, hdr->Max_Partitions));
25200f32ecbSAlexander Motin printf("Configuration_Record_Length %u\n", GET16(meta, hdr->Configuration_Record_Length));
25300f32ecbSAlexander Motin printf("Max_Primary_Element_Entries %u\n", GET16(meta, hdr->Max_Primary_Element_Entries));
25400f32ecbSAlexander Motin printf("Controller Data %u:%u\n", GET32(meta, hdr->cd_section), GET32(meta, hdr->cd_length));
25500f32ecbSAlexander Motin printf("Physical Disk %u:%u\n", GET32(meta, hdr->pdr_section), GET32(meta, hdr->pdr_length));
25600f32ecbSAlexander Motin printf("Virtual Disk %u:%u\n", GET32(meta, hdr->vdr_section), GET32(meta, hdr->vdr_length));
25700f32ecbSAlexander Motin printf("Configuration Recs %u:%u\n", GET32(meta, hdr->cr_section), GET32(meta, hdr->cr_length));
25800f32ecbSAlexander Motin printf("Physical Disk Recs %u:%u\n", GET32(meta, hdr->pdd_section), GET32(meta, hdr->pdd_length));
25900f32ecbSAlexander Motin printf("BBM Log %u:%u\n", GET32(meta, hdr->bbmlog_section), GET32(meta, hdr->bbmlog_length));
26000f32ecbSAlexander Motin printf("Diagnostic Space %u:%u\n", GET32(meta, hdr->Diagnostic_Space), GET32(meta, hdr->Diagnostic_Space_Length));
26100f32ecbSAlexander Motin printf("Vendor_Specific_Logs %u:%u\n", GET32(meta, hdr->Vendor_Specific_Logs), GET32(meta, hdr->Vendor_Specific_Logs_Length));
262310aef32SPedro F. Giffuni printf("**** Controller Data ****\n");
26300f32ecbSAlexander Motin printf("Controller_GUID ");
26400f32ecbSAlexander Motin print_guid(meta->cdr->Controller_GUID);
26500f32ecbSAlexander Motin printf("\n");
26600f32ecbSAlexander Motin printf("Controller_Type 0x%04x%04x 0x%04x%04x\n",
26700f32ecbSAlexander Motin GET16(meta, cdr->Controller_Type.Vendor_ID),
26800f32ecbSAlexander Motin GET16(meta, cdr->Controller_Type.Device_ID),
26900f32ecbSAlexander Motin GET16(meta, cdr->Controller_Type.SubVendor_ID),
27000f32ecbSAlexander Motin GET16(meta, cdr->Controller_Type.SubDevice_ID));
27100f32ecbSAlexander Motin printf("Product_ID '%.16s'\n", (char *)&meta->cdr->Product_ID[0]);
2722b9c925fSAlexander Motin printf("**** Physical Disk Records ****\n");
27300f32ecbSAlexander Motin printf("Populated_PDEs %u\n", GET16(meta, pdr->Populated_PDEs));
27400f32ecbSAlexander Motin printf("Max_PDE_Supported %u\n", GET16(meta, pdr->Max_PDE_Supported));
27500f32ecbSAlexander Motin for (j = 0; j < GET16(meta, pdr->Populated_PDEs); j++) {
27600f32ecbSAlexander Motin if (isff(meta->pdr->entry[j].PD_GUID, 24))
27700f32ecbSAlexander Motin continue;
27800f32ecbSAlexander Motin if (GET32(meta, pdr->entry[j].PD_Reference) == 0xffffffff)
27900f32ecbSAlexander Motin continue;
28000f32ecbSAlexander Motin printf("PD_GUID ");
28100f32ecbSAlexander Motin print_guid(meta->pdr->entry[j].PD_GUID);
28200f32ecbSAlexander Motin printf("\n");
28300f32ecbSAlexander Motin printf("PD_Reference 0x%08x\n",
28400f32ecbSAlexander Motin GET32(meta, pdr->entry[j].PD_Reference));
28500f32ecbSAlexander Motin printf("PD_Type 0x%04x\n",
28600f32ecbSAlexander Motin GET16(meta, pdr->entry[j].PD_Type));
28700f32ecbSAlexander Motin printf("PD_State 0x%04x\n",
28800f32ecbSAlexander Motin GET16(meta, pdr->entry[j].PD_State));
28900f32ecbSAlexander Motin printf("Configured_Size %ju\n",
29000f32ecbSAlexander Motin GET64(meta, pdr->entry[j].Configured_Size));
29100f32ecbSAlexander Motin printf("Block_Size %u\n",
29200f32ecbSAlexander Motin GET16(meta, pdr->entry[j].Block_Size));
29300f32ecbSAlexander Motin }
2942b9c925fSAlexander Motin printf("**** Virtual Disk Records ****\n");
29500f32ecbSAlexander Motin printf("Populated_VDEs %u\n", GET16(meta, vdr->Populated_VDEs));
29600f32ecbSAlexander Motin printf("Max_VDE_Supported %u\n", GET16(meta, vdr->Max_VDE_Supported));
29700f32ecbSAlexander Motin for (j = 0; j < GET16(meta, vdr->Populated_VDEs); j++) {
29800f32ecbSAlexander Motin if (isff(meta->vdr->entry[j].VD_GUID, 24))
29900f32ecbSAlexander Motin continue;
30000f32ecbSAlexander Motin printf("VD_GUID ");
30100f32ecbSAlexander Motin print_guid(meta->vdr->entry[j].VD_GUID);
30200f32ecbSAlexander Motin printf("\n");
30300f32ecbSAlexander Motin printf("VD_Number 0x%04x\n",
30400f32ecbSAlexander Motin GET16(meta, vdr->entry[j].VD_Number));
305d525d875SAlexander Motin printf("VD_Type 0x%04x\n",
306d525d875SAlexander Motin GET16(meta, vdr->entry[j].VD_Type));
30700f32ecbSAlexander Motin printf("VD_State 0x%02x\n",
30800f32ecbSAlexander Motin GET8(meta, vdr->entry[j].VD_State));
30900f32ecbSAlexander Motin printf("Init_State 0x%02x\n",
31000f32ecbSAlexander Motin GET8(meta, vdr->entry[j].Init_State));
31100f32ecbSAlexander Motin printf("Drive_Failures_Remaining %u\n",
31200f32ecbSAlexander Motin GET8(meta, vdr->entry[j].Drive_Failures_Remaining));
31300f32ecbSAlexander Motin printf("VD_Name '%.16s'\n",
31400f32ecbSAlexander Motin (char *)&meta->vdr->entry[j].VD_Name);
31500f32ecbSAlexander Motin }
31600f32ecbSAlexander Motin printf("**** Configuration Records ****\n");
3172b9c925fSAlexander Motin num = GETCRNUM(meta);
31800f32ecbSAlexander Motin for (j = 0; j < num; j++) {
3192b9c925fSAlexander Motin vdc = GETVDCPTR(meta, j);
32000f32ecbSAlexander Motin val = GET32D(meta, vdc->Signature);
32100f32ecbSAlexander Motin switch (val) {
32200f32ecbSAlexander Motin case DDF_VDCR_SIGNATURE:
32300f32ecbSAlexander Motin printf("** Virtual Disk Configuration **\n");
32400f32ecbSAlexander Motin printf("VD_GUID ");
32500f32ecbSAlexander Motin print_guid(vdc->VD_GUID);
32600f32ecbSAlexander Motin printf("\n");
32700f32ecbSAlexander Motin printf("Timestamp 0x%08x\n",
32800f32ecbSAlexander Motin GET32D(meta, vdc->Timestamp));
32900f32ecbSAlexander Motin printf("Sequence_Number 0x%08x\n",
33000f32ecbSAlexander Motin GET32D(meta, vdc->Sequence_Number));
33100f32ecbSAlexander Motin printf("Primary_Element_Count %u\n",
33200f32ecbSAlexander Motin GET16D(meta, vdc->Primary_Element_Count));
33300f32ecbSAlexander Motin printf("Stripe_Size %u\n",
33400f32ecbSAlexander Motin GET8D(meta, vdc->Stripe_Size));
33500f32ecbSAlexander Motin printf("Primary_RAID_Level 0x%02x\n",
33600f32ecbSAlexander Motin GET8D(meta, vdc->Primary_RAID_Level));
33700f32ecbSAlexander Motin printf("RLQ 0x%02x\n",
33800f32ecbSAlexander Motin GET8D(meta, vdc->RLQ));
33900f32ecbSAlexander Motin printf("Secondary_Element_Count %u\n",
34000f32ecbSAlexander Motin GET8D(meta, vdc->Secondary_Element_Count));
34100f32ecbSAlexander Motin printf("Secondary_Element_Seq %u\n",
34200f32ecbSAlexander Motin GET8D(meta, vdc->Secondary_Element_Seq));
34300f32ecbSAlexander Motin printf("Secondary_RAID_Level 0x%02x\n",
34400f32ecbSAlexander Motin GET8D(meta, vdc->Secondary_RAID_Level));
34500f32ecbSAlexander Motin printf("Block_Count %ju\n",
34600f32ecbSAlexander Motin GET64D(meta, vdc->Block_Count));
34700f32ecbSAlexander Motin printf("VD_Size %ju\n",
34800f32ecbSAlexander Motin GET64D(meta, vdc->VD_Size));
34900f32ecbSAlexander Motin printf("Block_Size %u\n",
35000f32ecbSAlexander Motin GET16D(meta, vdc->Block_Size));
35100f32ecbSAlexander Motin printf("Rotate_Parity_count %u\n",
35200f32ecbSAlexander Motin GET8D(meta, vdc->Rotate_Parity_count));
35300f32ecbSAlexander Motin printf("Associated_Spare_Disks");
35400f32ecbSAlexander Motin for (i = 0; i < 8; i++) {
35500f32ecbSAlexander Motin if (GET32D(meta, vdc->Associated_Spares[i]) != 0xffffffff)
35600f32ecbSAlexander Motin printf(" 0x%08x", GET32D(meta, vdc->Associated_Spares[i]));
35700f32ecbSAlexander Motin }
35800f32ecbSAlexander Motin printf("\n");
35900f32ecbSAlexander Motin printf("Cache_Flags %016jx\n",
36000f32ecbSAlexander Motin GET64D(meta, vdc->Cache_Flags));
36100f32ecbSAlexander Motin printf("BG_Rate %u\n",
36200f32ecbSAlexander Motin GET8D(meta, vdc->BG_Rate));
36300f32ecbSAlexander Motin printf("MDF_Parity_Disks %u\n",
36400f32ecbSAlexander Motin GET8D(meta, vdc->MDF_Parity_Disks));
36500f32ecbSAlexander Motin printf("MDF_Parity_Generator_Polynomial 0x%04x\n",
36600f32ecbSAlexander Motin GET16D(meta, vdc->MDF_Parity_Generator_Polynomial));
36700f32ecbSAlexander Motin printf("MDF_Constant_Generation_Method 0x%02x\n",
36800f32ecbSAlexander Motin GET8D(meta, vdc->MDF_Constant_Generation_Method));
36900f32ecbSAlexander Motin printf("Physical_Disks ");
37000f32ecbSAlexander Motin num2 = GET16D(meta, vdc->Primary_Element_Count);
37100f32ecbSAlexander Motin val2 = (uint64_t *)&(vdc->Physical_Disk_Sequence[GET16(meta, hdr->Max_Primary_Element_Entries)]);
37200f32ecbSAlexander Motin for (i = 0; i < num2; i++)
37300f32ecbSAlexander Motin printf(" 0x%08x @ %ju",
37400f32ecbSAlexander Motin GET32D(meta, vdc->Physical_Disk_Sequence[i]),
37500f32ecbSAlexander Motin GET64P(meta, val2 + i));
37600f32ecbSAlexander Motin printf("\n");
37700f32ecbSAlexander Motin break;
37800f32ecbSAlexander Motin case DDF_VUCR_SIGNATURE:
37900f32ecbSAlexander Motin printf("** Vendor Unique Configuration **\n");
38000f32ecbSAlexander Motin vuc = (struct ddf_vuc_record *)vdc;
38100f32ecbSAlexander Motin printf("VD_GUID ");
38200f32ecbSAlexander Motin print_guid(vuc->VD_GUID);
38300f32ecbSAlexander Motin printf("\n");
38400f32ecbSAlexander Motin break;
38500f32ecbSAlexander Motin case DDF_SA_SIGNATURE:
38600f32ecbSAlexander Motin printf("** Spare Assignment Configuration **\n");
38700f32ecbSAlexander Motin sa = (struct ddf_sa_record *)vdc;
38800f32ecbSAlexander Motin printf("Timestamp 0x%08x\n",
38900f32ecbSAlexander Motin GET32D(meta, sa->Timestamp));
39000f32ecbSAlexander Motin printf("Spare_Type 0x%02x\n",
39100f32ecbSAlexander Motin GET8D(meta, sa->Spare_Type));
39200f32ecbSAlexander Motin printf("Populated_SAEs %u\n",
39300f32ecbSAlexander Motin GET16D(meta, sa->Populated_SAEs));
39400f32ecbSAlexander Motin printf("MAX_SAE_Supported %u\n",
39500f32ecbSAlexander Motin GET16D(meta, sa->MAX_SAE_Supported));
39600f32ecbSAlexander Motin for (i = 0; i < GET16D(meta, sa->Populated_SAEs); i++) {
39700f32ecbSAlexander Motin if (isff(sa->entry[i].VD_GUID, 24))
39800f32ecbSAlexander Motin continue;
39900f32ecbSAlexander Motin printf("VD_GUID ");
40000f32ecbSAlexander Motin for (k = 0; k < 24; k++)
40100f32ecbSAlexander Motin printf("%02x", sa->entry[i].VD_GUID[k]);
40200f32ecbSAlexander Motin printf("\n");
40300f32ecbSAlexander Motin printf("Secondary_Element %u\n",
40400f32ecbSAlexander Motin GET16D(meta, sa->entry[i].Secondary_Element));
40500f32ecbSAlexander Motin }
40600f32ecbSAlexander Motin break;
407d525d875SAlexander Motin case 0x00000000:
40800f32ecbSAlexander Motin case 0xFFFFFFFF:
40900f32ecbSAlexander Motin break;
41000f32ecbSAlexander Motin default:
41100f32ecbSAlexander Motin printf("Unknown configuration signature %08x\n", val);
41200f32ecbSAlexander Motin break;
41300f32ecbSAlexander Motin }
41400f32ecbSAlexander Motin }
41500f32ecbSAlexander Motin printf("**** Physical Disk Data ****\n");
41600f32ecbSAlexander Motin printf("PD_GUID ");
41700f32ecbSAlexander Motin print_guid(meta->pdd->PD_GUID);
41800f32ecbSAlexander Motin printf("\n");
41900f32ecbSAlexander Motin printf("PD_Reference 0x%08x\n",
42000f32ecbSAlexander Motin GET32(meta, pdd->PD_Reference));
42100f32ecbSAlexander Motin printf("Forced_Ref_Flag 0x%02x\n",
42200f32ecbSAlexander Motin GET8(meta, pdd->Forced_Ref_Flag));
42300f32ecbSAlexander Motin printf("Forced_PD_GUID_Flag 0x%02x\n",
42400f32ecbSAlexander Motin GET8(meta, pdd->Forced_PD_GUID_Flag));
42500f32ecbSAlexander Motin }
42600f32ecbSAlexander Motin
42700f32ecbSAlexander Motin static int
ddf_meta_find_pd(struct ddf_meta * meta,uint8_t * GUID,uint32_t PD_Reference)42800f32ecbSAlexander Motin ddf_meta_find_pd(struct ddf_meta *meta, uint8_t *GUID, uint32_t PD_Reference)
42900f32ecbSAlexander Motin {
43000f32ecbSAlexander Motin int i;
43100f32ecbSAlexander Motin
43200f32ecbSAlexander Motin for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
43300f32ecbSAlexander Motin if (GUID != NULL) {
43400f32ecbSAlexander Motin if (memcmp(meta->pdr->entry[i].PD_GUID, GUID, 24) == 0)
43500f32ecbSAlexander Motin return (i);
43600f32ecbSAlexander Motin } else if (PD_Reference != 0xffffffff) {
43700f32ecbSAlexander Motin if (GET32(meta, pdr->entry[i].PD_Reference) == PD_Reference)
43800f32ecbSAlexander Motin return (i);
43900f32ecbSAlexander Motin } else
44000f32ecbSAlexander Motin if (isff(meta->pdr->entry[i].PD_GUID, 24))
44100f32ecbSAlexander Motin return (i);
44200f32ecbSAlexander Motin }
44300f32ecbSAlexander Motin if (GUID == NULL && PD_Reference == 0xffffffff) {
44400f32ecbSAlexander Motin if (i >= GET16(meta, pdr->Max_PDE_Supported))
44500f32ecbSAlexander Motin return (-1);
44600f32ecbSAlexander Motin SET16(meta, pdr->Populated_PDEs, i + 1);
44700f32ecbSAlexander Motin return (i);
44800f32ecbSAlexander Motin }
44900f32ecbSAlexander Motin return (-1);
45000f32ecbSAlexander Motin }
45100f32ecbSAlexander Motin
45200f32ecbSAlexander Motin static int
ddf_meta_find_vd(struct ddf_meta * meta,uint8_t * GUID)45300f32ecbSAlexander Motin ddf_meta_find_vd(struct ddf_meta *meta, uint8_t *GUID)
45400f32ecbSAlexander Motin {
45500f32ecbSAlexander Motin int i;
45600f32ecbSAlexander Motin
45700f32ecbSAlexander Motin for (i = 0; i < GET16(meta, vdr->Populated_VDEs); i++) {
45800f32ecbSAlexander Motin if (GUID != NULL) {
45900f32ecbSAlexander Motin if (memcmp(meta->vdr->entry[i].VD_GUID, GUID, 24) == 0)
46000f32ecbSAlexander Motin return (i);
46100f32ecbSAlexander Motin } else
46200f32ecbSAlexander Motin if (isff(meta->vdr->entry[i].VD_GUID, 24))
46300f32ecbSAlexander Motin return (i);
46400f32ecbSAlexander Motin }
46500f32ecbSAlexander Motin if (GUID == NULL) {
46600f32ecbSAlexander Motin if (i >= GET16(meta, vdr->Max_VDE_Supported))
46700f32ecbSAlexander Motin return (-1);
46800f32ecbSAlexander Motin SET16(meta, vdr->Populated_VDEs, i + 1);
46900f32ecbSAlexander Motin return (i);
47000f32ecbSAlexander Motin }
47100f32ecbSAlexander Motin return (-1);
47200f32ecbSAlexander Motin }
47300f32ecbSAlexander Motin
47400f32ecbSAlexander Motin static struct ddf_vdc_record *
ddf_meta_find_vdc(struct ddf_meta * meta,uint8_t * GUID)47500f32ecbSAlexander Motin ddf_meta_find_vdc(struct ddf_meta *meta, uint8_t *GUID)
47600f32ecbSAlexander Motin {
47700f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
47800f32ecbSAlexander Motin int i, num;
47900f32ecbSAlexander Motin
4802b9c925fSAlexander Motin num = GETCRNUM(meta);
48100f32ecbSAlexander Motin for (i = 0; i < num; i++) {
4822b9c925fSAlexander Motin vdc = GETVDCPTR(meta, i);
48300f32ecbSAlexander Motin if (GUID != NULL) {
48400f32ecbSAlexander Motin if (GET32D(meta, vdc->Signature) == DDF_VDCR_SIGNATURE &&
48500f32ecbSAlexander Motin memcmp(vdc->VD_GUID, GUID, 24) == 0)
48600f32ecbSAlexander Motin return (vdc);
48700f32ecbSAlexander Motin } else
488d525d875SAlexander Motin if (GET32D(meta, vdc->Signature) == 0xffffffff ||
489d525d875SAlexander Motin GET32D(meta, vdc->Signature) == 0)
49000f32ecbSAlexander Motin return (vdc);
49100f32ecbSAlexander Motin }
49200f32ecbSAlexander Motin return (NULL);
49300f32ecbSAlexander Motin }
49400f32ecbSAlexander Motin
49500f32ecbSAlexander Motin static int
ddf_meta_count_vdc(struct ddf_meta * meta,uint8_t * GUID)49600f32ecbSAlexander Motin ddf_meta_count_vdc(struct ddf_meta *meta, uint8_t *GUID)
49700f32ecbSAlexander Motin {
49800f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
49900f32ecbSAlexander Motin int i, num, cnt;
50000f32ecbSAlexander Motin
50100f32ecbSAlexander Motin cnt = 0;
5022b9c925fSAlexander Motin num = GETCRNUM(meta);
50300f32ecbSAlexander Motin for (i = 0; i < num; i++) {
5042b9c925fSAlexander Motin vdc = GETVDCPTR(meta, i);
50500f32ecbSAlexander Motin if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
50600f32ecbSAlexander Motin continue;
50700f32ecbSAlexander Motin if (GUID == NULL || memcmp(vdc->VD_GUID, GUID, 24) == 0)
50800f32ecbSAlexander Motin cnt++;
50900f32ecbSAlexander Motin }
51000f32ecbSAlexander Motin return (cnt);
51100f32ecbSAlexander Motin }
51200f32ecbSAlexander Motin
51300f32ecbSAlexander Motin static int
ddf_meta_find_disk(struct ddf_vol_meta * vmeta,uint32_t PD_Reference,int * bvdp,int * posp)51400f32ecbSAlexander Motin ddf_meta_find_disk(struct ddf_vol_meta *vmeta, uint32_t PD_Reference,
51500f32ecbSAlexander Motin int *bvdp, int *posp)
51600f32ecbSAlexander Motin {
51700f32ecbSAlexander Motin int i, bvd, pos;
51800f32ecbSAlexander Motin
51900f32ecbSAlexander Motin i = 0;
52057eed4a8SAlexander Motin for (bvd = 0; bvd < GET8(vmeta, vdc->Secondary_Element_Count); bvd++) {
52100f32ecbSAlexander Motin if (vmeta->bvdc[bvd] == NULL) {
52200f32ecbSAlexander Motin i += GET16(vmeta, vdc->Primary_Element_Count); // XXX
52300f32ecbSAlexander Motin continue;
52400f32ecbSAlexander Motin }
52500f32ecbSAlexander Motin for (pos = 0; pos < GET16(vmeta, bvdc[bvd]->Primary_Element_Count);
52600f32ecbSAlexander Motin pos++, i++) {
52700f32ecbSAlexander Motin if (GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]) ==
52800f32ecbSAlexander Motin PD_Reference) {
52900f32ecbSAlexander Motin if (bvdp != NULL)
53000f32ecbSAlexander Motin *bvdp = bvd;
53100f32ecbSAlexander Motin if (posp != NULL)
53200f32ecbSAlexander Motin *posp = pos;
53300f32ecbSAlexander Motin return (i);
53400f32ecbSAlexander Motin }
53500f32ecbSAlexander Motin }
53600f32ecbSAlexander Motin }
53700f32ecbSAlexander Motin return (-1);
53800f32ecbSAlexander Motin }
53900f32ecbSAlexander Motin
540d525d875SAlexander Motin static struct ddf_sa_record *
ddf_meta_find_sa(struct ddf_meta * meta,int create)541d525d875SAlexander Motin ddf_meta_find_sa(struct ddf_meta *meta, int create)
542d525d875SAlexander Motin {
543d525d875SAlexander Motin struct ddf_sa_record *sa;
544d525d875SAlexander Motin int i, num;
545d525d875SAlexander Motin
546d525d875SAlexander Motin num = GETCRNUM(meta);
547d525d875SAlexander Motin for (i = 0; i < num; i++) {
548d525d875SAlexander Motin sa = GETSAPTR(meta, i);
549d525d875SAlexander Motin if (GET32D(meta, sa->Signature) == DDF_SA_SIGNATURE)
550d525d875SAlexander Motin return (sa);
551d525d875SAlexander Motin }
552d525d875SAlexander Motin if (create) {
553d525d875SAlexander Motin for (i = 0; i < num; i++) {
554d525d875SAlexander Motin sa = GETSAPTR(meta, i);
555d525d875SAlexander Motin if (GET32D(meta, sa->Signature) == 0xffffffff ||
556d525d875SAlexander Motin GET32D(meta, sa->Signature) == 0)
557d525d875SAlexander Motin return (sa);
558d525d875SAlexander Motin }
559d525d875SAlexander Motin }
560d525d875SAlexander Motin return (NULL);
561d525d875SAlexander Motin }
562d525d875SAlexander Motin
56300f32ecbSAlexander Motin static void
ddf_meta_create(struct g_raid_disk * disk,struct ddf_meta * sample)56400f32ecbSAlexander Motin ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
56500f32ecbSAlexander Motin {
56600f32ecbSAlexander Motin struct timespec ts;
56700f32ecbSAlexander Motin struct clocktime ct;
56800f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
5698df8e26aSAlexander Motin struct g_raid_md_ddf_object *mdi;
57000f32ecbSAlexander Motin struct ddf_meta *meta;
57100f32ecbSAlexander Motin struct ddf_pd_entry *pde;
57200f32ecbSAlexander Motin off_t anchorlba;
57300f32ecbSAlexander Motin u_int ss, pos, size;
57400f32ecbSAlexander Motin int len, error;
5752c385d51SSean Bruno char serial_buffer[DISK_IDENT_SIZE];
57600f32ecbSAlexander Motin
57700f32ecbSAlexander Motin if (sample->hdr == NULL)
57800f32ecbSAlexander Motin sample = NULL;
57900f32ecbSAlexander Motin
5808df8e26aSAlexander Motin mdi = (struct g_raid_md_ddf_object *)disk->d_softc->sc_md;
58100f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
58200f32ecbSAlexander Motin meta = &pd->pd_meta;
58300f32ecbSAlexander Motin ss = disk->d_consumer->provider->sectorsize;
58400f32ecbSAlexander Motin anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
58500f32ecbSAlexander Motin
58600f32ecbSAlexander Motin meta->sectorsize = ss;
5878df8e26aSAlexander Motin meta->bigendian = sample ? sample->bigendian : mdi->mdio_bigendian;
58800f32ecbSAlexander Motin getnanotime(&ts);
58900f32ecbSAlexander Motin clock_ts_to_ct(&ts, &ct);
59000f32ecbSAlexander Motin
59100f32ecbSAlexander Motin /* Header */
59200f32ecbSAlexander Motin meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
59300f32ecbSAlexander Motin memset(meta->hdr, 0xff, ss);
59400f32ecbSAlexander Motin if (sample) {
59500f32ecbSAlexander Motin memcpy(meta->hdr, sample->hdr, sizeof(struct ddf_header));
59600f32ecbSAlexander Motin if (ss != sample->sectorsize) {
59700f32ecbSAlexander Motin SET32(meta, hdr->WorkSpace_Length,
59855e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->WorkSpace_Length) *
59955e0987aSPedro F. Giffuni sample->sectorsize, ss));
60000f32ecbSAlexander Motin SET16(meta, hdr->Configuration_Record_Length,
60155e0987aSPedro F. Giffuni howmany(GET16(sample,
60255e0987aSPedro F. Giffuni hdr->Configuration_Record_Length) *
60355e0987aSPedro F. Giffuni sample->sectorsize, ss));
60400f32ecbSAlexander Motin SET32(meta, hdr->cd_length,
60555e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->cd_length) *
60655e0987aSPedro F. Giffuni sample->sectorsize, ss));
60700f32ecbSAlexander Motin SET32(meta, hdr->pdr_length,
60855e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->pdr_length) *
60955e0987aSPedro F. Giffuni sample->sectorsize, ss));
61000f32ecbSAlexander Motin SET32(meta, hdr->vdr_length,
61155e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->vdr_length) *
61255e0987aSPedro F. Giffuni sample->sectorsize, ss));
61300f32ecbSAlexander Motin SET32(meta, hdr->cr_length,
61455e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->cr_length) *
61555e0987aSPedro F. Giffuni sample->sectorsize, ss));
61600f32ecbSAlexander Motin SET32(meta, hdr->pdd_length,
61755e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->pdd_length) *
61855e0987aSPedro F. Giffuni sample->sectorsize, ss));
61900f32ecbSAlexander Motin SET32(meta, hdr->bbmlog_length,
62055e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->bbmlog_length) *
62155e0987aSPedro F. Giffuni sample->sectorsize, ss));
62200f32ecbSAlexander Motin SET32(meta, hdr->Diagnostic_Space,
62355e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->bbmlog_length) *
62455e0987aSPedro F. Giffuni sample->sectorsize, ss));
62500f32ecbSAlexander Motin SET32(meta, hdr->Vendor_Specific_Logs,
62655e0987aSPedro F. Giffuni howmany(GET32(sample, hdr->bbmlog_length) *
62755e0987aSPedro F. Giffuni sample->sectorsize, ss));
62800f32ecbSAlexander Motin }
62900f32ecbSAlexander Motin } else {
63000f32ecbSAlexander Motin SET32(meta, hdr->Signature, DDF_HEADER_SIGNATURE);
63100f32ecbSAlexander Motin snprintf(meta->hdr->DDF_Header_GUID, 25, "FreeBSD %08x%08x",
63200f32ecbSAlexander Motin (u_int)(ts.tv_sec - DECADE), arc4random());
63300f32ecbSAlexander Motin memcpy(meta->hdr->DDF_rev, "02.00.00", 8);
63400f32ecbSAlexander Motin SET32(meta, hdr->TimeStamp, (ts.tv_sec - DECADE));
63500f32ecbSAlexander Motin SET32(meta, hdr->WorkSpace_Length, 16 * 1024 * 1024 / ss);
63600f32ecbSAlexander Motin SET16(meta, hdr->Max_PD_Entries, DDF_MAX_DISKS - 1);
63700f32ecbSAlexander Motin SET16(meta, hdr->Max_VD_Entries, DDF_MAX_VDISKS);
63800f32ecbSAlexander Motin SET16(meta, hdr->Max_Partitions, DDF_MAX_PARTITIONS);
63900f32ecbSAlexander Motin SET16(meta, hdr->Max_Primary_Element_Entries, DDF_MAX_DISKS);
64000f32ecbSAlexander Motin SET16(meta, hdr->Configuration_Record_Length,
64155e0987aSPedro F. Giffuni howmany(sizeof(struct ddf_vdc_record) + (4 + 8) *
64255e0987aSPedro F. Giffuni GET16(meta, hdr->Max_Primary_Element_Entries), ss));
64300f32ecbSAlexander Motin SET32(meta, hdr->cd_length,
64455e0987aSPedro F. Giffuni howmany(sizeof(struct ddf_cd_record), ss));
64500f32ecbSAlexander Motin SET32(meta, hdr->pdr_length,
64655e0987aSPedro F. Giffuni howmany(sizeof(struct ddf_pd_record) +
64755e0987aSPedro F. Giffuni sizeof(struct ddf_pd_entry) * GET16(meta,
64855e0987aSPedro F. Giffuni hdr->Max_PD_Entries), ss));
64900f32ecbSAlexander Motin SET32(meta, hdr->vdr_length,
65055e0987aSPedro F. Giffuni howmany(sizeof(struct ddf_vd_record) +
65100f32ecbSAlexander Motin sizeof(struct ddf_vd_entry) *
65255e0987aSPedro F. Giffuni GET16(meta, hdr->Max_VD_Entries), ss));
65300f32ecbSAlexander Motin SET32(meta, hdr->cr_length,
65400f32ecbSAlexander Motin GET16(meta, hdr->Configuration_Record_Length) *
65500f32ecbSAlexander Motin (GET16(meta, hdr->Max_Partitions) + 1));
65600f32ecbSAlexander Motin SET32(meta, hdr->pdd_length,
65755e0987aSPedro F. Giffuni howmany(sizeof(struct ddf_pdd_record), ss));
65800f32ecbSAlexander Motin SET32(meta, hdr->bbmlog_length, 0);
65900f32ecbSAlexander Motin SET32(meta, hdr->Diagnostic_Space_Length, 0);
66000f32ecbSAlexander Motin SET32(meta, hdr->Vendor_Specific_Logs_Length, 0);
66100f32ecbSAlexander Motin }
66200f32ecbSAlexander Motin pos = 1;
66300f32ecbSAlexander Motin SET32(meta, hdr->cd_section, pos);
66400f32ecbSAlexander Motin pos += GET32(meta, hdr->cd_length);
66500f32ecbSAlexander Motin SET32(meta, hdr->pdr_section, pos);
66600f32ecbSAlexander Motin pos += GET32(meta, hdr->pdr_length);
66700f32ecbSAlexander Motin SET32(meta, hdr->vdr_section, pos);
66800f32ecbSAlexander Motin pos += GET32(meta, hdr->vdr_length);
66900f32ecbSAlexander Motin SET32(meta, hdr->cr_section, pos);
67000f32ecbSAlexander Motin pos += GET32(meta, hdr->cr_length);
67100f32ecbSAlexander Motin SET32(meta, hdr->pdd_section, pos);
67200f32ecbSAlexander Motin pos += GET32(meta, hdr->pdd_length);
67300f32ecbSAlexander Motin SET32(meta, hdr->bbmlog_section,
67400f32ecbSAlexander Motin GET32(meta, hdr->bbmlog_length) != 0 ? pos : 0xffffffff);
67500f32ecbSAlexander Motin pos += GET32(meta, hdr->bbmlog_length);
67600f32ecbSAlexander Motin SET32(meta, hdr->Diagnostic_Space,
67700f32ecbSAlexander Motin GET32(meta, hdr->Diagnostic_Space_Length) != 0 ? pos : 0xffffffff);
67800f32ecbSAlexander Motin pos += GET32(meta, hdr->Diagnostic_Space_Length);
67900f32ecbSAlexander Motin SET32(meta, hdr->Vendor_Specific_Logs,
68000f32ecbSAlexander Motin GET32(meta, hdr->Vendor_Specific_Logs_Length) != 0 ? pos : 0xffffffff);
681d525d875SAlexander Motin pos += min(GET32(meta, hdr->Vendor_Specific_Logs_Length), 1);
68200f32ecbSAlexander Motin SET64(meta, hdr->Primary_Header_LBA,
683d525d875SAlexander Motin anchorlba - pos);
68400f32ecbSAlexander Motin SET64(meta, hdr->Secondary_Header_LBA,
68500f32ecbSAlexander Motin 0xffffffffffffffffULL);
68600f32ecbSAlexander Motin SET64(meta, hdr->WorkSpace_LBA,
68700f32ecbSAlexander Motin anchorlba + 1 - 32 * 1024 * 1024 / ss);
68800f32ecbSAlexander Motin
68900f32ecbSAlexander Motin /* Controller Data */
69000f32ecbSAlexander Motin size = GET32(meta, hdr->cd_length) * ss;
69100f32ecbSAlexander Motin meta->cdr = malloc(size, M_MD_DDF, M_WAITOK);
69200f32ecbSAlexander Motin memset(meta->cdr, 0xff, size);
69300f32ecbSAlexander Motin SET32(meta, cdr->Signature, DDF_CONTROLLER_DATA_SIGNATURE);
69400f32ecbSAlexander Motin memcpy(meta->cdr->Controller_GUID, "FreeBSD GEOM RAID SERIAL", 24);
69500f32ecbSAlexander Motin memcpy(meta->cdr->Product_ID, "FreeBSD GEOMRAID", 16);
69600f32ecbSAlexander Motin
69700f32ecbSAlexander Motin /* Physical Drive Records. */
69800f32ecbSAlexander Motin size = GET32(meta, hdr->pdr_length) * ss;
69900f32ecbSAlexander Motin meta->pdr = malloc(size, M_MD_DDF, M_WAITOK);
70000f32ecbSAlexander Motin memset(meta->pdr, 0xff, size);
70100f32ecbSAlexander Motin SET32(meta, pdr->Signature, DDF_PDR_SIGNATURE);
70200f32ecbSAlexander Motin SET16(meta, pdr->Populated_PDEs, 1);
70300f32ecbSAlexander Motin SET16(meta, pdr->Max_PDE_Supported,
70400f32ecbSAlexander Motin GET16(meta, hdr->Max_PD_Entries));
70500f32ecbSAlexander Motin
70600f32ecbSAlexander Motin pde = &meta->pdr->entry[0];
70700f32ecbSAlexander Motin len = sizeof(serial_buffer);
70800f32ecbSAlexander Motin error = g_io_getattr("GEOM::ident", disk->d_consumer, &len, serial_buffer);
70900f32ecbSAlexander Motin if (error == 0 && (len = strlen (serial_buffer)) >= 6 && len <= 20)
71000f32ecbSAlexander Motin snprintf(pde->PD_GUID, 25, "DISK%20s", serial_buffer);
71100f32ecbSAlexander Motin else
71200f32ecbSAlexander Motin snprintf(pde->PD_GUID, 25, "DISK%04d%02d%02d%08x%04x",
71300f32ecbSAlexander Motin ct.year, ct.mon, ct.day,
71400f32ecbSAlexander Motin arc4random(), arc4random() & 0xffff);
71500f32ecbSAlexander Motin SET32D(meta, pde->PD_Reference, arc4random());
71600f32ecbSAlexander Motin SET16D(meta, pde->PD_Type, DDF_PDE_GUID_FORCE);
71700f32ecbSAlexander Motin SET16D(meta, pde->PD_State, 0);
71800f32ecbSAlexander Motin SET64D(meta, pde->Configured_Size,
71900f32ecbSAlexander Motin anchorlba + 1 - 32 * 1024 * 1024 / ss);
72000f32ecbSAlexander Motin SET16D(meta, pde->Block_Size, ss);
72100f32ecbSAlexander Motin
72200f32ecbSAlexander Motin /* Virtual Drive Records. */
72300f32ecbSAlexander Motin size = GET32(meta, hdr->vdr_length) * ss;
72400f32ecbSAlexander Motin meta->vdr = malloc(size, M_MD_DDF, M_WAITOK);
72500f32ecbSAlexander Motin memset(meta->vdr, 0xff, size);
72600f32ecbSAlexander Motin SET32(meta, vdr->Signature, DDF_VD_RECORD_SIGNATURE);
72700f32ecbSAlexander Motin SET32(meta, vdr->Populated_VDEs, 0);
72800f32ecbSAlexander Motin SET16(meta, vdr->Max_VDE_Supported,
72900f32ecbSAlexander Motin GET16(meta, hdr->Max_VD_Entries));
73000f32ecbSAlexander Motin
73100f32ecbSAlexander Motin /* Configuration Records. */
73200f32ecbSAlexander Motin size = GET32(meta, hdr->cr_length) * ss;
73300f32ecbSAlexander Motin meta->cr = malloc(size, M_MD_DDF, M_WAITOK);
73400f32ecbSAlexander Motin memset(meta->cr, 0xff, size);
73500f32ecbSAlexander Motin
73600f32ecbSAlexander Motin /* Physical Disk Data. */
73700f32ecbSAlexander Motin size = GET32(meta, hdr->pdd_length) * ss;
73800f32ecbSAlexander Motin meta->pdd = malloc(size, M_MD_DDF, M_WAITOK);
73900f32ecbSAlexander Motin memset(meta->pdd, 0xff, size);
74000f32ecbSAlexander Motin SET32(meta, pdd->Signature, DDF_PDD_SIGNATURE);
74100f32ecbSAlexander Motin memcpy(meta->pdd->PD_GUID, pde->PD_GUID, 24);
74200f32ecbSAlexander Motin SET32(meta, pdd->PD_Reference, GET32D(meta, pde->PD_Reference));
74300f32ecbSAlexander Motin SET8(meta, pdd->Forced_Ref_Flag, DDF_PDD_FORCED_REF);
74400f32ecbSAlexander Motin SET8(meta, pdd->Forced_PD_GUID_Flag, DDF_PDD_FORCED_GUID);
74500f32ecbSAlexander Motin
74600f32ecbSAlexander Motin /* Bad Block Management Log. */
74700f32ecbSAlexander Motin if (GET32(meta, hdr->bbmlog_length) != 0) {
74800f32ecbSAlexander Motin size = GET32(meta, hdr->bbmlog_length) * ss;
74900f32ecbSAlexander Motin meta->bbm = malloc(size, M_MD_DDF, M_WAITOK);
75000f32ecbSAlexander Motin memset(meta->bbm, 0xff, size);
75100f32ecbSAlexander Motin SET32(meta, bbm->Signature, DDF_BBML_SIGNATURE);
75200f32ecbSAlexander Motin SET32(meta, bbm->Entry_Count, 0);
75300f32ecbSAlexander Motin SET32(meta, bbm->Spare_Block_Count, 0);
75400f32ecbSAlexander Motin }
75500f32ecbSAlexander Motin }
75600f32ecbSAlexander Motin
75700f32ecbSAlexander Motin static void
ddf_meta_copy(struct ddf_meta * dst,struct ddf_meta * src)75800f32ecbSAlexander Motin ddf_meta_copy(struct ddf_meta *dst, struct ddf_meta *src)
75900f32ecbSAlexander Motin {
76000f32ecbSAlexander Motin u_int ss;
76100f32ecbSAlexander Motin
76200f32ecbSAlexander Motin dst->bigendian = src->bigendian;
76300f32ecbSAlexander Motin ss = dst->sectorsize = src->sectorsize;
76400f32ecbSAlexander Motin dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
76500f32ecbSAlexander Motin memcpy(dst->hdr, src->hdr, ss);
76600f32ecbSAlexander Motin dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
76700f32ecbSAlexander Motin memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
76800f32ecbSAlexander Motin dst->pdr = malloc(GET32(src, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
76900f32ecbSAlexander Motin memcpy(dst->pdr, src->pdr, GET32(src, hdr->pdr_length) * ss);
77000f32ecbSAlexander Motin dst->vdr = malloc(GET32(src, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
77100f32ecbSAlexander Motin memcpy(dst->vdr, src->vdr, GET32(src, hdr->vdr_length) * ss);
77200f32ecbSAlexander Motin dst->cr = malloc(GET32(src, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
77300f32ecbSAlexander Motin memcpy(dst->cr, src->cr, GET32(src, hdr->cr_length) * ss);
77400f32ecbSAlexander Motin dst->pdd = malloc(GET32(src, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
77500f32ecbSAlexander Motin memcpy(dst->pdd, src->pdd, GET32(src, hdr->pdd_length) * ss);
77600f32ecbSAlexander Motin if (src->bbm != NULL) {
77700f32ecbSAlexander Motin dst->bbm = malloc(GET32(src, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
77800f32ecbSAlexander Motin memcpy(dst->bbm, src->bbm, GET32(src, hdr->bbmlog_length) * ss);
77900f32ecbSAlexander Motin }
78000f32ecbSAlexander Motin }
78100f32ecbSAlexander Motin
78200f32ecbSAlexander Motin static void
ddf_meta_update(struct ddf_meta * meta,struct ddf_meta * src)78300f32ecbSAlexander Motin ddf_meta_update(struct ddf_meta *meta, struct ddf_meta *src)
78400f32ecbSAlexander Motin {
78500f32ecbSAlexander Motin struct ddf_pd_entry *pde, *spde;
78600f32ecbSAlexander Motin int i, j;
78700f32ecbSAlexander Motin
78800f32ecbSAlexander Motin for (i = 0; i < GET16(src, pdr->Populated_PDEs); i++) {
78900f32ecbSAlexander Motin spde = &src->pdr->entry[i];
79000f32ecbSAlexander Motin if (isff(spde->PD_GUID, 24))
79100f32ecbSAlexander Motin continue;
79200f32ecbSAlexander Motin j = ddf_meta_find_pd(meta, NULL,
79386b03669SAlexander Motin GET32(src, pdr->entry[i].PD_Reference));
79400f32ecbSAlexander Motin if (j < 0) {
79500f32ecbSAlexander Motin j = ddf_meta_find_pd(meta, NULL, 0xffffffff);
79600f32ecbSAlexander Motin pde = &meta->pdr->entry[j];
79700f32ecbSAlexander Motin memcpy(pde, spde, sizeof(*pde));
79800f32ecbSAlexander Motin } else {
79900f32ecbSAlexander Motin pde = &meta->pdr->entry[j];
80000f32ecbSAlexander Motin SET16D(meta, pde->PD_State,
80100f32ecbSAlexander Motin GET16D(meta, pde->PD_State) |
80200f32ecbSAlexander Motin GET16D(src, pde->PD_State));
80300f32ecbSAlexander Motin }
80400f32ecbSAlexander Motin }
80500f32ecbSAlexander Motin }
80600f32ecbSAlexander Motin
80700f32ecbSAlexander Motin static void
ddf_meta_free(struct ddf_meta * meta)80800f32ecbSAlexander Motin ddf_meta_free(struct ddf_meta *meta)
80900f32ecbSAlexander Motin {
81000f32ecbSAlexander Motin
81100f32ecbSAlexander Motin if (meta->hdr != NULL) {
81200f32ecbSAlexander Motin free(meta->hdr, M_MD_DDF);
81300f32ecbSAlexander Motin meta->hdr = NULL;
81400f32ecbSAlexander Motin }
81500f32ecbSAlexander Motin if (meta->cdr != NULL) {
81600f32ecbSAlexander Motin free(meta->cdr, M_MD_DDF);
81700f32ecbSAlexander Motin meta->cdr = NULL;
81800f32ecbSAlexander Motin }
81900f32ecbSAlexander Motin if (meta->pdr != NULL) {
82000f32ecbSAlexander Motin free(meta->pdr, M_MD_DDF);
82100f32ecbSAlexander Motin meta->pdr = NULL;
82200f32ecbSAlexander Motin }
82300f32ecbSAlexander Motin if (meta->vdr != NULL) {
82400f32ecbSAlexander Motin free(meta->vdr, M_MD_DDF);
82500f32ecbSAlexander Motin meta->vdr = NULL;
82600f32ecbSAlexander Motin }
82700f32ecbSAlexander Motin if (meta->cr != NULL) {
82800f32ecbSAlexander Motin free(meta->cr, M_MD_DDF);
82900f32ecbSAlexander Motin meta->cr = NULL;
83000f32ecbSAlexander Motin }
83100f32ecbSAlexander Motin if (meta->pdd != NULL) {
83200f32ecbSAlexander Motin free(meta->pdd, M_MD_DDF);
83300f32ecbSAlexander Motin meta->pdd = NULL;
83400f32ecbSAlexander Motin }
83500f32ecbSAlexander Motin if (meta->bbm != NULL) {
83600f32ecbSAlexander Motin free(meta->bbm, M_MD_DDF);
83700f32ecbSAlexander Motin meta->bbm = NULL;
83800f32ecbSAlexander Motin }
83900f32ecbSAlexander Motin }
84000f32ecbSAlexander Motin
84100f32ecbSAlexander Motin static void
ddf_vol_meta_create(struct ddf_vol_meta * meta,struct ddf_meta * sample)84200f32ecbSAlexander Motin ddf_vol_meta_create(struct ddf_vol_meta *meta, struct ddf_meta *sample)
84300f32ecbSAlexander Motin {
84400f32ecbSAlexander Motin struct timespec ts;
84500f32ecbSAlexander Motin struct clocktime ct;
84600f32ecbSAlexander Motin u_int ss, size;
84700f32ecbSAlexander Motin
84800f32ecbSAlexander Motin meta->bigendian = sample->bigendian;
84900f32ecbSAlexander Motin ss = meta->sectorsize = sample->sectorsize;
85000f32ecbSAlexander Motin meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
85100f32ecbSAlexander Motin memcpy(meta->hdr, sample->hdr, ss);
85200f32ecbSAlexander Motin meta->cdr = malloc(GET32(sample, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
85300f32ecbSAlexander Motin memcpy(meta->cdr, sample->cdr, GET32(sample, hdr->cd_length) * ss);
85400f32ecbSAlexander Motin meta->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
85500f32ecbSAlexander Motin memset(meta->vde, 0xff, sizeof(struct ddf_vd_entry));
85600f32ecbSAlexander Motin getnanotime(&ts);
85700f32ecbSAlexander Motin clock_ts_to_ct(&ts, &ct);
85800f32ecbSAlexander Motin snprintf(meta->vde->VD_GUID, 25, "FreeBSD%04d%02d%02d%08x%01x",
85900f32ecbSAlexander Motin ct.year, ct.mon, ct.day,
86000f32ecbSAlexander Motin arc4random(), arc4random() & 0xf);
86100f32ecbSAlexander Motin size = GET16(sample, hdr->Configuration_Record_Length) * ss;
86200f32ecbSAlexander Motin meta->vdc = malloc(size, M_MD_DDF, M_WAITOK);
86300f32ecbSAlexander Motin memset(meta->vdc, 0xff, size);
86400f32ecbSAlexander Motin SET32(meta, vdc->Signature, DDF_VDCR_SIGNATURE);
86500f32ecbSAlexander Motin memcpy(meta->vdc->VD_GUID, meta->vde->VD_GUID, 24);
86600f32ecbSAlexander Motin SET32(meta, vdc->Sequence_Number, 0);
86700f32ecbSAlexander Motin }
86800f32ecbSAlexander Motin
86900f32ecbSAlexander Motin static void
ddf_vol_meta_update(struct ddf_vol_meta * dst,struct ddf_meta * src,uint8_t * GUID,int started)87047e98096SAlexander Motin ddf_vol_meta_update(struct ddf_vol_meta *dst, struct ddf_meta *src,
87147e98096SAlexander Motin uint8_t *GUID, int started)
87200f32ecbSAlexander Motin {
87300f32ecbSAlexander Motin struct ddf_vd_entry *vde;
87400f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
87500f32ecbSAlexander Motin int vnew, bvnew, bvd, size;
87600f32ecbSAlexander Motin u_int ss;
87700f32ecbSAlexander Motin
87800f32ecbSAlexander Motin vde = &src->vdr->entry[ddf_meta_find_vd(src, GUID)];
87900f32ecbSAlexander Motin vdc = ddf_meta_find_vdc(src, GUID);
88034d3281cSAlexander Motin if (GET8D(src, vdc->Secondary_Element_Count) == 1)
88134d3281cSAlexander Motin bvd = 0;
88234d3281cSAlexander Motin else
88300f32ecbSAlexander Motin bvd = GET8D(src, vdc->Secondary_Element_Seq);
88400f32ecbSAlexander Motin size = GET16(src, hdr->Configuration_Record_Length) * src->sectorsize;
88500f32ecbSAlexander Motin
88600f32ecbSAlexander Motin if (dst->vdc == NULL ||
88747e98096SAlexander Motin (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
88847e98096SAlexander Motin GET32(dst, vdc->Sequence_Number))) > 0))
88900f32ecbSAlexander Motin vnew = 1;
89000f32ecbSAlexander Motin else
89100f32ecbSAlexander Motin vnew = 0;
89200f32ecbSAlexander Motin
89300f32ecbSAlexander Motin if (dst->bvdc[bvd] == NULL ||
89447e98096SAlexander Motin (!started && ((int32_t)(GET32D(src, vdc->Sequence_Number) -
89547e98096SAlexander Motin GET32(dst, bvdc[bvd]->Sequence_Number))) > 0))
89600f32ecbSAlexander Motin bvnew = 1;
89700f32ecbSAlexander Motin else
89800f32ecbSAlexander Motin bvnew = 0;
89900f32ecbSAlexander Motin
90000f32ecbSAlexander Motin if (vnew) {
90100f32ecbSAlexander Motin dst->bigendian = src->bigendian;
90200f32ecbSAlexander Motin ss = dst->sectorsize = src->sectorsize;
90300f32ecbSAlexander Motin if (dst->hdr != NULL)
90400f32ecbSAlexander Motin free(dst->hdr, M_MD_DDF);
90500f32ecbSAlexander Motin dst->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
90600f32ecbSAlexander Motin memcpy(dst->hdr, src->hdr, ss);
90700f32ecbSAlexander Motin if (dst->cdr != NULL)
90800f32ecbSAlexander Motin free(dst->cdr, M_MD_DDF);
90900f32ecbSAlexander Motin dst->cdr = malloc(GET32(src, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
91000f32ecbSAlexander Motin memcpy(dst->cdr, src->cdr, GET32(src, hdr->cd_length) * ss);
91100f32ecbSAlexander Motin if (dst->vde != NULL)
91200f32ecbSAlexander Motin free(dst->vde, M_MD_DDF);
91300f32ecbSAlexander Motin dst->vde = malloc(sizeof(struct ddf_vd_entry), M_MD_DDF, M_WAITOK);
91400f32ecbSAlexander Motin memcpy(dst->vde, vde, sizeof(struct ddf_vd_entry));
91500f32ecbSAlexander Motin if (dst->vdc != NULL)
91600f32ecbSAlexander Motin free(dst->vdc, M_MD_DDF);
91700f32ecbSAlexander Motin dst->vdc = malloc(size, M_MD_DDF, M_WAITOK);
91800f32ecbSAlexander Motin memcpy(dst->vdc, vdc, size);
91900f32ecbSAlexander Motin }
92000f32ecbSAlexander Motin if (bvnew) {
92100f32ecbSAlexander Motin if (dst->bvdc[bvd] != NULL)
92200f32ecbSAlexander Motin free(dst->bvdc[bvd], M_MD_DDF);
92300f32ecbSAlexander Motin dst->bvdc[bvd] = malloc(size, M_MD_DDF, M_WAITOK);
92400f32ecbSAlexander Motin memcpy(dst->bvdc[bvd], vdc, size);
92500f32ecbSAlexander Motin }
92600f32ecbSAlexander Motin }
92700f32ecbSAlexander Motin
92800f32ecbSAlexander Motin static void
ddf_vol_meta_free(struct ddf_vol_meta * meta)92900f32ecbSAlexander Motin ddf_vol_meta_free(struct ddf_vol_meta *meta)
93000f32ecbSAlexander Motin {
93100f32ecbSAlexander Motin int i;
93200f32ecbSAlexander Motin
93300f32ecbSAlexander Motin if (meta->hdr != NULL) {
93400f32ecbSAlexander Motin free(meta->hdr, M_MD_DDF);
93500f32ecbSAlexander Motin meta->hdr = NULL;
93600f32ecbSAlexander Motin }
93700f32ecbSAlexander Motin if (meta->cdr != NULL) {
93800f32ecbSAlexander Motin free(meta->cdr, M_MD_DDF);
93900f32ecbSAlexander Motin meta->cdr = NULL;
94000f32ecbSAlexander Motin }
94100f32ecbSAlexander Motin if (meta->vde != NULL) {
94200f32ecbSAlexander Motin free(meta->vde, M_MD_DDF);
94300f32ecbSAlexander Motin meta->vde = NULL;
94400f32ecbSAlexander Motin }
94500f32ecbSAlexander Motin if (meta->vdc != NULL) {
94600f32ecbSAlexander Motin free(meta->vdc, M_MD_DDF);
94700f32ecbSAlexander Motin meta->vdc = NULL;
94800f32ecbSAlexander Motin }
94900f32ecbSAlexander Motin for (i = 0; i < DDF_MAX_DISKS_HARD; i++) {
95000f32ecbSAlexander Motin if (meta->bvdc[i] != NULL) {
95100f32ecbSAlexander Motin free(meta->bvdc[i], M_MD_DDF);
95200f32ecbSAlexander Motin meta->bvdc[i] = NULL;
95300f32ecbSAlexander Motin }
95400f32ecbSAlexander Motin }
95500f32ecbSAlexander Motin }
95600f32ecbSAlexander Motin
95700f32ecbSAlexander Motin static int
ddf_meta_unused_range(struct ddf_meta * meta,off_t * off,off_t * size)95800f32ecbSAlexander Motin ddf_meta_unused_range(struct ddf_meta *meta, off_t *off, off_t *size)
95900f32ecbSAlexander Motin {
96000f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
96100f32ecbSAlexander Motin off_t beg[32], end[32], beg1, end1;
96200f32ecbSAlexander Motin uint64_t *offp;
96300f32ecbSAlexander Motin int i, j, n, num, pos;
96400f32ecbSAlexander Motin uint32_t ref;
96500f32ecbSAlexander Motin
96600f32ecbSAlexander Motin *off = 0;
96700f32ecbSAlexander Motin *size = 0;
96800f32ecbSAlexander Motin ref = GET32(meta, pdd->PD_Reference);
96900f32ecbSAlexander Motin pos = ddf_meta_find_pd(meta, NULL, ref);
97000f32ecbSAlexander Motin beg[0] = 0;
97100f32ecbSAlexander Motin end[0] = GET64(meta, pdr->entry[pos].Configured_Size);
97200f32ecbSAlexander Motin n = 1;
9732b9c925fSAlexander Motin num = GETCRNUM(meta);
97400f32ecbSAlexander Motin for (i = 0; i < num; i++) {
9752b9c925fSAlexander Motin vdc = GETVDCPTR(meta, i);
97600f32ecbSAlexander Motin if (GET32D(meta, vdc->Signature) != DDF_VDCR_SIGNATURE)
97700f32ecbSAlexander Motin continue;
97800f32ecbSAlexander Motin for (pos = 0; pos < GET16D(meta, vdc->Primary_Element_Count); pos++)
97900f32ecbSAlexander Motin if (GET32D(meta, vdc->Physical_Disk_Sequence[pos]) == ref)
98000f32ecbSAlexander Motin break;
98100f32ecbSAlexander Motin if (pos == GET16D(meta, vdc->Primary_Element_Count))
98200f32ecbSAlexander Motin continue;
98300f32ecbSAlexander Motin offp = (uint64_t *)&(vdc->Physical_Disk_Sequence[
98400f32ecbSAlexander Motin GET16(meta, hdr->Max_Primary_Element_Entries)]);
98500f32ecbSAlexander Motin beg1 = GET64P(meta, offp + pos);
98600f32ecbSAlexander Motin end1 = beg1 + GET64D(meta, vdc->Block_Count);
98700f32ecbSAlexander Motin for (j = 0; j < n; j++) {
98800f32ecbSAlexander Motin if (beg[j] >= end1 || end[j] <= beg1 )
98900f32ecbSAlexander Motin continue;
99000f32ecbSAlexander Motin if (beg[j] < beg1 && end[j] > end1) {
99100f32ecbSAlexander Motin beg[n] = end1;
99200f32ecbSAlexander Motin end[n] = end[j];
99300f32ecbSAlexander Motin end[j] = beg1;
99400f32ecbSAlexander Motin n++;
99500f32ecbSAlexander Motin } else if (beg[j] < beg1)
99600f32ecbSAlexander Motin end[j] = beg1;
99700f32ecbSAlexander Motin else
99800f32ecbSAlexander Motin beg[j] = end1;
99900f32ecbSAlexander Motin }
100000f32ecbSAlexander Motin }
100100f32ecbSAlexander Motin for (j = 0; j < n; j++) {
100200f32ecbSAlexander Motin if (end[j] - beg[j] > *size) {
100300f32ecbSAlexander Motin *off = beg[j];
100400f32ecbSAlexander Motin *size = end[j] - beg[j];
100500f32ecbSAlexander Motin }
100600f32ecbSAlexander Motin }
100700f32ecbSAlexander Motin return ((*size > 0) ? 1 : 0);
100800f32ecbSAlexander Motin }
100900f32ecbSAlexander Motin
101000f32ecbSAlexander Motin static void
ddf_meta_get_name(struct ddf_meta * meta,int num,char * buf)101100f32ecbSAlexander Motin ddf_meta_get_name(struct ddf_meta *meta, int num, char *buf)
101200f32ecbSAlexander Motin {
101300f32ecbSAlexander Motin const char *b;
101400f32ecbSAlexander Motin int i;
101500f32ecbSAlexander Motin
101600f32ecbSAlexander Motin b = meta->vdr->entry[num].VD_Name;
101700f32ecbSAlexander Motin for (i = 15; i >= 0; i--)
101800f32ecbSAlexander Motin if (b[i] != 0x20)
101900f32ecbSAlexander Motin break;
102000f32ecbSAlexander Motin memcpy(buf, b, i + 1);
102100f32ecbSAlexander Motin buf[i + 1] = 0;
102200f32ecbSAlexander Motin }
102300f32ecbSAlexander Motin
102400f32ecbSAlexander Motin static void
ddf_meta_put_name(struct ddf_vol_meta * meta,char * buf)102500f32ecbSAlexander Motin ddf_meta_put_name(struct ddf_vol_meta *meta, char *buf)
102600f32ecbSAlexander Motin {
102700f32ecbSAlexander Motin int len;
102800f32ecbSAlexander Motin
102900f32ecbSAlexander Motin len = min(strlen(buf), 16);
103000f32ecbSAlexander Motin memset(meta->vde->VD_Name, 0x20, 16);
103100f32ecbSAlexander Motin memcpy(meta->vde->VD_Name, buf, len);
103200f32ecbSAlexander Motin }
103300f32ecbSAlexander Motin
103400f32ecbSAlexander Motin static int
ddf_meta_read(struct g_consumer * cp,struct ddf_meta * meta)103500f32ecbSAlexander Motin ddf_meta_read(struct g_consumer *cp, struct ddf_meta *meta)
103600f32ecbSAlexander Motin {
103700f32ecbSAlexander Motin struct g_provider *pp;
103800f32ecbSAlexander Motin struct ddf_header *ahdr, *hdr;
103900f32ecbSAlexander Motin char *abuf, *buf;
104000f32ecbSAlexander Motin off_t plba, slba, lba;
104100f32ecbSAlexander Motin int error, len, i;
104200f32ecbSAlexander Motin u_int ss;
104300f32ecbSAlexander Motin uint32_t val;
104400f32ecbSAlexander Motin
104500f32ecbSAlexander Motin ddf_meta_free(meta);
10469e9ba9c7SMark Johnston
104700f32ecbSAlexander Motin pp = cp->provider;
104800f32ecbSAlexander Motin ss = meta->sectorsize = pp->sectorsize;
10499e9ba9c7SMark Johnston if (ss < sizeof(*hdr))
10509e9ba9c7SMark Johnston return (ENXIO);
105100f32ecbSAlexander Motin /* Read anchor block. */
105200f32ecbSAlexander Motin abuf = g_read_data(cp, pp->mediasize - ss, ss, &error);
105300f32ecbSAlexander Motin if (abuf == NULL) {
105400f32ecbSAlexander Motin G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).",
105500f32ecbSAlexander Motin pp->name, error);
105600f32ecbSAlexander Motin return (error);
105700f32ecbSAlexander Motin }
105800f32ecbSAlexander Motin ahdr = (struct ddf_header *)abuf;
105900f32ecbSAlexander Motin
106000f32ecbSAlexander Motin /* Check if this is an DDF RAID struct */
106100f32ecbSAlexander Motin if (be32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
106200f32ecbSAlexander Motin meta->bigendian = 1;
106300f32ecbSAlexander Motin else if (le32dec(&ahdr->Signature) == DDF_HEADER_SIGNATURE)
106400f32ecbSAlexander Motin meta->bigendian = 0;
106500f32ecbSAlexander Motin else {
106600f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF signature check failed on %s", pp->name);
106700f32ecbSAlexander Motin error = EINVAL;
106800f32ecbSAlexander Motin goto done;
106900f32ecbSAlexander Motin }
107000f32ecbSAlexander Motin if (ahdr->Header_Type != DDF_HEADER_ANCHOR) {
107100f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF header type check failed on %s", pp->name);
107200f32ecbSAlexander Motin error = EINVAL;
107300f32ecbSAlexander Motin goto done;
107400f32ecbSAlexander Motin }
107500f32ecbSAlexander Motin meta->hdr = ahdr;
107600f32ecbSAlexander Motin plba = GET64(meta, hdr->Primary_Header_LBA);
107700f32ecbSAlexander Motin slba = GET64(meta, hdr->Secondary_Header_LBA);
107800f32ecbSAlexander Motin val = GET32(meta, hdr->CRC);
107900f32ecbSAlexander Motin SET32(meta, hdr->CRC, 0xffffffff);
108000f32ecbSAlexander Motin meta->hdr = NULL;
108100f32ecbSAlexander Motin if (crc32(ahdr, ss) != val) {
108200f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF CRC mismatch on %s", pp->name);
108300f32ecbSAlexander Motin error = EINVAL;
108400f32ecbSAlexander Motin goto done;
108500f32ecbSAlexander Motin }
108600f32ecbSAlexander Motin if ((plba + 6) * ss >= pp->mediasize) {
108700f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF primary header LBA is wrong on %s", pp->name);
108800f32ecbSAlexander Motin error = EINVAL;
108900f32ecbSAlexander Motin goto done;
109000f32ecbSAlexander Motin }
109100f32ecbSAlexander Motin if (slba != -1 && (slba + 6) * ss >= pp->mediasize) {
109200f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF secondary header LBA is wrong on %s", pp->name);
109300f32ecbSAlexander Motin error = EINVAL;
109400f32ecbSAlexander Motin goto done;
109500f32ecbSAlexander Motin }
109600f32ecbSAlexander Motin lba = plba;
109700f32ecbSAlexander Motin
109800f32ecbSAlexander Motin doread:
109900f32ecbSAlexander Motin error = 0;
110000f32ecbSAlexander Motin ddf_meta_free(meta);
110100f32ecbSAlexander Motin
110200f32ecbSAlexander Motin /* Read header block. */
110300f32ecbSAlexander Motin buf = g_read_data(cp, lba * ss, ss, &error);
110400f32ecbSAlexander Motin if (buf == NULL) {
110500f32ecbSAlexander Motin readerror:
110600f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF %s metadata read error on %s (error=%d).",
110700f32ecbSAlexander Motin (lba == plba) ? "primary" : "secondary", pp->name, error);
110800f32ecbSAlexander Motin if (lba == plba && slba != -1) {
110900f32ecbSAlexander Motin lba = slba;
111000f32ecbSAlexander Motin goto doread;
111100f32ecbSAlexander Motin }
111200f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF metadata read error on %s.", pp->name);
111300f32ecbSAlexander Motin goto done;
111400f32ecbSAlexander Motin }
111500f32ecbSAlexander Motin meta->hdr = malloc(ss, M_MD_DDF, M_WAITOK);
111600f32ecbSAlexander Motin memcpy(meta->hdr, buf, ss);
111700f32ecbSAlexander Motin g_free(buf);
111800f32ecbSAlexander Motin hdr = meta->hdr;
111900f32ecbSAlexander Motin val = GET32(meta, hdr->CRC);
112000f32ecbSAlexander Motin SET32(meta, hdr->CRC, 0xffffffff);
112100f32ecbSAlexander Motin if (hdr->Signature != ahdr->Signature ||
112200f32ecbSAlexander Motin crc32(meta->hdr, ss) != val ||
112300f32ecbSAlexander Motin memcmp(hdr->DDF_Header_GUID, ahdr->DDF_Header_GUID, 24) ||
112400f32ecbSAlexander Motin GET64(meta, hdr->Primary_Header_LBA) != plba ||
112500f32ecbSAlexander Motin GET64(meta, hdr->Secondary_Header_LBA) != slba) {
112600f32ecbSAlexander Motin hdrerror:
112700f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF %s metadata check failed on %s",
112800f32ecbSAlexander Motin (lba == plba) ? "primary" : "secondary", pp->name);
112900f32ecbSAlexander Motin if (lba == plba && slba != -1) {
113000f32ecbSAlexander Motin lba = slba;
113100f32ecbSAlexander Motin goto doread;
113200f32ecbSAlexander Motin }
113300f32ecbSAlexander Motin G_RAID_DEBUG(1, "DDF metadata check failed on %s", pp->name);
113400f32ecbSAlexander Motin error = EINVAL;
113500f32ecbSAlexander Motin goto done;
113600f32ecbSAlexander Motin }
113700f32ecbSAlexander Motin if ((lba == plba && hdr->Header_Type != DDF_HEADER_PRIMARY) ||
113800f32ecbSAlexander Motin (lba == slba && hdr->Header_Type != DDF_HEADER_SECONDARY))
113900f32ecbSAlexander Motin goto hdrerror;
114000f32ecbSAlexander Motin len = 1;
114100f32ecbSAlexander Motin len = max(len, GET32(meta, hdr->cd_section) + GET32(meta, hdr->cd_length));
114200f32ecbSAlexander Motin len = max(len, GET32(meta, hdr->pdr_section) + GET32(meta, hdr->pdr_length));
114300f32ecbSAlexander Motin len = max(len, GET32(meta, hdr->vdr_section) + GET32(meta, hdr->vdr_length));
114400f32ecbSAlexander Motin len = max(len, GET32(meta, hdr->cr_section) + GET32(meta, hdr->cr_length));
114500f32ecbSAlexander Motin len = max(len, GET32(meta, hdr->pdd_section) + GET32(meta, hdr->pdd_length));
114600f32ecbSAlexander Motin if ((val = GET32(meta, hdr->bbmlog_section)) != 0xffffffff)
114700f32ecbSAlexander Motin len = max(len, val + GET32(meta, hdr->bbmlog_length));
114800f32ecbSAlexander Motin if ((val = GET32(meta, hdr->Diagnostic_Space)) != 0xffffffff)
114900f32ecbSAlexander Motin len = max(len, val + GET32(meta, hdr->Diagnostic_Space_Length));
115000f32ecbSAlexander Motin if ((val = GET32(meta, hdr->Vendor_Specific_Logs)) != 0xffffffff)
115100f32ecbSAlexander Motin len = max(len, val + GET32(meta, hdr->Vendor_Specific_Logs_Length));
115200f32ecbSAlexander Motin if ((plba + len) * ss >= pp->mediasize)
115300f32ecbSAlexander Motin goto hdrerror;
115400f32ecbSAlexander Motin if (slba != -1 && (slba + len) * ss >= pp->mediasize)
115500f32ecbSAlexander Motin goto hdrerror;
115600f32ecbSAlexander Motin /* Workaround for Adaptec implementation. */
115700f32ecbSAlexander Motin if (GET16(meta, hdr->Max_Primary_Element_Entries) == 0xffff) {
115800f32ecbSAlexander Motin SET16(meta, hdr->Max_Primary_Element_Entries,
115900f32ecbSAlexander Motin min(GET16(meta, hdr->Max_PD_Entries),
116000f32ecbSAlexander Motin (GET16(meta, hdr->Configuration_Record_Length) * ss - 512) / 12));
116100f32ecbSAlexander Motin }
116200f32ecbSAlexander Motin
1163cd853791SKonstantin Belousov if (GET32(meta, hdr->cd_length) * ss >= maxphys ||
1164cd853791SKonstantin Belousov GET32(meta, hdr->pdr_length) * ss >= maxphys ||
1165cd853791SKonstantin Belousov GET32(meta, hdr->vdr_length) * ss >= maxphys ||
1166cd853791SKonstantin Belousov GET32(meta, hdr->cr_length) * ss >= maxphys ||
1167cd853791SKonstantin Belousov GET32(meta, hdr->pdd_length) * ss >= maxphys ||
1168cd853791SKonstantin Belousov GET32(meta, hdr->bbmlog_length) * ss >= maxphys) {
1169b28ea2c2SConrad Meyer G_RAID_DEBUG(1, "%s: Blocksize is too big.", pp->name);
1170b28ea2c2SConrad Meyer goto hdrerror;
1171b28ea2c2SConrad Meyer }
1172b28ea2c2SConrad Meyer
117300f32ecbSAlexander Motin /* Read controller data. */
117400f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
117500f32ecbSAlexander Motin GET32(meta, hdr->cd_length) * ss, &error);
117600f32ecbSAlexander Motin if (buf == NULL)
117700f32ecbSAlexander Motin goto readerror;
117800f32ecbSAlexander Motin meta->cdr = malloc(GET32(meta, hdr->cd_length) * ss, M_MD_DDF, M_WAITOK);
117900f32ecbSAlexander Motin memcpy(meta->cdr, buf, GET32(meta, hdr->cd_length) * ss);
118000f32ecbSAlexander Motin g_free(buf);
118100f32ecbSAlexander Motin if (GET32(meta, cdr->Signature) != DDF_CONTROLLER_DATA_SIGNATURE)
118200f32ecbSAlexander Motin goto hdrerror;
118300f32ecbSAlexander Motin
118400f32ecbSAlexander Motin /* Read physical disk records. */
118500f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
118600f32ecbSAlexander Motin GET32(meta, hdr->pdr_length) * ss, &error);
118700f32ecbSAlexander Motin if (buf == NULL)
118800f32ecbSAlexander Motin goto readerror;
118900f32ecbSAlexander Motin meta->pdr = malloc(GET32(meta, hdr->pdr_length) * ss, M_MD_DDF, M_WAITOK);
119000f32ecbSAlexander Motin memcpy(meta->pdr, buf, GET32(meta, hdr->pdr_length) * ss);
119100f32ecbSAlexander Motin g_free(buf);
119200f32ecbSAlexander Motin if (GET32(meta, pdr->Signature) != DDF_PDR_SIGNATURE)
119300f32ecbSAlexander Motin goto hdrerror;
11941229e83dSAlexander Motin /*
11951229e83dSAlexander Motin * Workaround for reading metadata corrupted due to graid bug.
11961229e83dSAlexander Motin * XXX: Remove this before we have disks above 128PB. :)
11971229e83dSAlexander Motin */
11981229e83dSAlexander Motin if (meta->bigendian) {
11991229e83dSAlexander Motin for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
12001229e83dSAlexander Motin if (isff(meta->pdr->entry[i].PD_GUID, 24))
12011229e83dSAlexander Motin continue;
12021229e83dSAlexander Motin if (GET32(meta, pdr->entry[i].PD_Reference) ==
12031229e83dSAlexander Motin 0xffffffff)
12041229e83dSAlexander Motin continue;
12051229e83dSAlexander Motin if (GET64(meta, pdr->entry[i].Configured_Size) >=
12061229e83dSAlexander Motin (1ULL << 48)) {
12071229e83dSAlexander Motin SET16(meta, pdr->entry[i].PD_State,
12081229e83dSAlexander Motin GET16(meta, pdr->entry[i].PD_State) &
12091229e83dSAlexander Motin ~DDF_PDE_FAILED);
12101229e83dSAlexander Motin SET64(meta, pdr->entry[i].Configured_Size,
12111229e83dSAlexander Motin GET64(meta, pdr->entry[i].Configured_Size) &
12121229e83dSAlexander Motin ((1ULL << 48) - 1));
12131229e83dSAlexander Motin }
12141229e83dSAlexander Motin }
12151229e83dSAlexander Motin }
121600f32ecbSAlexander Motin
121700f32ecbSAlexander Motin /* Read virtual disk records. */
121800f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
121900f32ecbSAlexander Motin GET32(meta, hdr->vdr_length) * ss, &error);
122000f32ecbSAlexander Motin if (buf == NULL)
122100f32ecbSAlexander Motin goto readerror;
122200f32ecbSAlexander Motin meta->vdr = malloc(GET32(meta, hdr->vdr_length) * ss, M_MD_DDF, M_WAITOK);
122300f32ecbSAlexander Motin memcpy(meta->vdr, buf, GET32(meta, hdr->vdr_length) * ss);
122400f32ecbSAlexander Motin g_free(buf);
122500f32ecbSAlexander Motin if (GET32(meta, vdr->Signature) != DDF_VD_RECORD_SIGNATURE)
122600f32ecbSAlexander Motin goto hdrerror;
122700f32ecbSAlexander Motin
122800f32ecbSAlexander Motin /* Read configuration records. */
122900f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
123000f32ecbSAlexander Motin GET32(meta, hdr->cr_length) * ss, &error);
123100f32ecbSAlexander Motin if (buf == NULL)
123200f32ecbSAlexander Motin goto readerror;
123300f32ecbSAlexander Motin meta->cr = malloc(GET32(meta, hdr->cr_length) * ss, M_MD_DDF, M_WAITOK);
123400f32ecbSAlexander Motin memcpy(meta->cr, buf, GET32(meta, hdr->cr_length) * ss);
123500f32ecbSAlexander Motin g_free(buf);
123600f32ecbSAlexander Motin
123700f32ecbSAlexander Motin /* Read physical disk data. */
123800f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
123900f32ecbSAlexander Motin GET32(meta, hdr->pdd_length) * ss, &error);
124000f32ecbSAlexander Motin if (buf == NULL)
124100f32ecbSAlexander Motin goto readerror;
124200f32ecbSAlexander Motin meta->pdd = malloc(GET32(meta, hdr->pdd_length) * ss, M_MD_DDF, M_WAITOK);
124300f32ecbSAlexander Motin memcpy(meta->pdd, buf, GET32(meta, hdr->pdd_length) * ss);
124400f32ecbSAlexander Motin g_free(buf);
124500f32ecbSAlexander Motin if (GET32(meta, pdd->Signature) != DDF_PDD_SIGNATURE)
124600f32ecbSAlexander Motin goto hdrerror;
124700f32ecbSAlexander Motin i = ddf_meta_find_pd(meta, NULL, GET32(meta, pdd->PD_Reference));
124800f32ecbSAlexander Motin if (i < 0)
124900f32ecbSAlexander Motin goto hdrerror;
125000f32ecbSAlexander Motin
125100f32ecbSAlexander Motin /* Read BBM Log. */
125200f32ecbSAlexander Motin if (GET32(meta, hdr->bbmlog_section) != 0xffffffff &&
125300f32ecbSAlexander Motin GET32(meta, hdr->bbmlog_length) != 0) {
125400f32ecbSAlexander Motin buf = g_read_data(cp, (lba + GET32(meta, hdr->bbmlog_section)) * ss,
125500f32ecbSAlexander Motin GET32(meta, hdr->bbmlog_length) * ss, &error);
125600f32ecbSAlexander Motin if (buf == NULL)
125700f32ecbSAlexander Motin goto readerror;
125800f32ecbSAlexander Motin meta->bbm = malloc(GET32(meta, hdr->bbmlog_length) * ss, M_MD_DDF, M_WAITOK);
125900f32ecbSAlexander Motin memcpy(meta->bbm, buf, GET32(meta, hdr->bbmlog_length) * ss);
126000f32ecbSAlexander Motin g_free(buf);
126100f32ecbSAlexander Motin if (GET32(meta, bbm->Signature) != DDF_BBML_SIGNATURE)
126200f32ecbSAlexander Motin goto hdrerror;
126300f32ecbSAlexander Motin }
126400f32ecbSAlexander Motin
126500f32ecbSAlexander Motin done:
1266eb3b1cd0SAlexander Motin g_free(abuf);
126700f32ecbSAlexander Motin if (error != 0)
126800f32ecbSAlexander Motin ddf_meta_free(meta);
126900f32ecbSAlexander Motin return (error);
127000f32ecbSAlexander Motin }
127100f32ecbSAlexander Motin
127200f32ecbSAlexander Motin static int
ddf_meta_write(struct g_consumer * cp,struct ddf_meta * meta)127300f32ecbSAlexander Motin ddf_meta_write(struct g_consumer *cp, struct ddf_meta *meta)
127400f32ecbSAlexander Motin {
127500f32ecbSAlexander Motin struct g_provider *pp;
127600f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
127700f32ecbSAlexander Motin off_t alba, plba, slba, lba;
127800f32ecbSAlexander Motin u_int ss, size;
127900f32ecbSAlexander Motin int error, i, num;
128000f32ecbSAlexander Motin
128100f32ecbSAlexander Motin pp = cp->provider;
128200f32ecbSAlexander Motin ss = pp->sectorsize;
128300f32ecbSAlexander Motin lba = alba = pp->mediasize / ss - 1;
128400f32ecbSAlexander Motin plba = GET64(meta, hdr->Primary_Header_LBA);
128500f32ecbSAlexander Motin slba = GET64(meta, hdr->Secondary_Header_LBA);
128600f32ecbSAlexander Motin
128700f32ecbSAlexander Motin next:
128800f32ecbSAlexander Motin SET8(meta, hdr->Header_Type, (lba == alba) ? DDF_HEADER_ANCHOR :
128900f32ecbSAlexander Motin (lba == plba) ? DDF_HEADER_PRIMARY : DDF_HEADER_SECONDARY);
129000f32ecbSAlexander Motin SET32(meta, hdr->CRC, 0xffffffff);
129100f32ecbSAlexander Motin SET32(meta, hdr->CRC, crc32(meta->hdr, ss));
129200f32ecbSAlexander Motin error = g_write_data(cp, lba * ss, meta->hdr, ss);
129300f32ecbSAlexander Motin if (error != 0) {
129400f32ecbSAlexander Motin err:
129500f32ecbSAlexander Motin G_RAID_DEBUG(1, "Cannot write metadata to %s (error=%d).",
129600f32ecbSAlexander Motin pp->name, error);
129700f32ecbSAlexander Motin if (lba != alba)
129800f32ecbSAlexander Motin goto done;
129900f32ecbSAlexander Motin }
130000f32ecbSAlexander Motin if (lba == alba) {
130100f32ecbSAlexander Motin lba = plba;
130200f32ecbSAlexander Motin goto next;
130300f32ecbSAlexander Motin }
130400f32ecbSAlexander Motin
130500f32ecbSAlexander Motin size = GET32(meta, hdr->cd_length) * ss;
130600f32ecbSAlexander Motin SET32(meta, cdr->CRC, 0xffffffff);
130700f32ecbSAlexander Motin SET32(meta, cdr->CRC, crc32(meta->cdr, size));
130800f32ecbSAlexander Motin error = g_write_data(cp, (lba + GET32(meta, hdr->cd_section)) * ss,
130900f32ecbSAlexander Motin meta->cdr, size);
131000f32ecbSAlexander Motin if (error != 0)
131100f32ecbSAlexander Motin goto err;
131200f32ecbSAlexander Motin
131300f32ecbSAlexander Motin size = GET32(meta, hdr->pdr_length) * ss;
131400f32ecbSAlexander Motin SET32(meta, pdr->CRC, 0xffffffff);
131500f32ecbSAlexander Motin SET32(meta, pdr->CRC, crc32(meta->pdr, size));
131600f32ecbSAlexander Motin error = g_write_data(cp, (lba + GET32(meta, hdr->pdr_section)) * ss,
131700f32ecbSAlexander Motin meta->pdr, size);
131800f32ecbSAlexander Motin if (error != 0)
131900f32ecbSAlexander Motin goto err;
132000f32ecbSAlexander Motin
132100f32ecbSAlexander Motin size = GET32(meta, hdr->vdr_length) * ss;
132200f32ecbSAlexander Motin SET32(meta, vdr->CRC, 0xffffffff);
132300f32ecbSAlexander Motin SET32(meta, vdr->CRC, crc32(meta->vdr, size));
132400f32ecbSAlexander Motin error = g_write_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
132500f32ecbSAlexander Motin meta->vdr, size);
132600f32ecbSAlexander Motin if (error != 0)
132700f32ecbSAlexander Motin goto err;
132800f32ecbSAlexander Motin
13292b9c925fSAlexander Motin size = GET16(meta, hdr->Configuration_Record_Length) * ss;
13302b9c925fSAlexander Motin num = GETCRNUM(meta);
133100f32ecbSAlexander Motin for (i = 0; i < num; i++) {
13322b9c925fSAlexander Motin vdc = GETVDCPTR(meta, i);
133300f32ecbSAlexander Motin SET32D(meta, vdc->CRC, 0xffffffff);
133400f32ecbSAlexander Motin SET32D(meta, vdc->CRC, crc32(vdc, size));
133500f32ecbSAlexander Motin }
133600f32ecbSAlexander Motin error = g_write_data(cp, (lba + GET32(meta, hdr->cr_section)) * ss,
133700f32ecbSAlexander Motin meta->cr, size * num);
133800f32ecbSAlexander Motin if (error != 0)
133900f32ecbSAlexander Motin goto err;
134000f32ecbSAlexander Motin
134100f32ecbSAlexander Motin size = GET32(meta, hdr->pdd_length) * ss;
134200f32ecbSAlexander Motin SET32(meta, pdd->CRC, 0xffffffff);
134300f32ecbSAlexander Motin SET32(meta, pdd->CRC, crc32(meta->pdd, size));
134400f32ecbSAlexander Motin error = g_write_data(cp, (lba + GET32(meta, hdr->pdd_section)) * ss,
134500f32ecbSAlexander Motin meta->pdd, size);
134600f32ecbSAlexander Motin if (error != 0)
134700f32ecbSAlexander Motin goto err;
134800f32ecbSAlexander Motin
134900f32ecbSAlexander Motin if (GET32(meta, hdr->bbmlog_length) != 0) {
135000f32ecbSAlexander Motin size = GET32(meta, hdr->bbmlog_length) * ss;
135100f32ecbSAlexander Motin SET32(meta, bbm->CRC, 0xffffffff);
135200f32ecbSAlexander Motin SET32(meta, bbm->CRC, crc32(meta->bbm, size));
135300f32ecbSAlexander Motin error = g_write_data(cp,
135400f32ecbSAlexander Motin (lba + GET32(meta, hdr->bbmlog_section)) * ss,
135500f32ecbSAlexander Motin meta->bbm, size);
135600f32ecbSAlexander Motin if (error != 0)
135700f32ecbSAlexander Motin goto err;
135800f32ecbSAlexander Motin }
135900f32ecbSAlexander Motin
136000f32ecbSAlexander Motin done:
136100f32ecbSAlexander Motin if (lba == plba && slba != -1) {
136200f32ecbSAlexander Motin lba = slba;
136300f32ecbSAlexander Motin goto next;
136400f32ecbSAlexander Motin }
136500f32ecbSAlexander Motin
136600f32ecbSAlexander Motin return (error);
136700f32ecbSAlexander Motin }
136800f32ecbSAlexander Motin
136900f32ecbSAlexander Motin static int
ddf_meta_erase(struct g_consumer * cp)137000f32ecbSAlexander Motin ddf_meta_erase(struct g_consumer *cp)
137100f32ecbSAlexander Motin {
137200f32ecbSAlexander Motin struct g_provider *pp;
137300f32ecbSAlexander Motin char *buf;
137400f32ecbSAlexander Motin int error;
137500f32ecbSAlexander Motin
137600f32ecbSAlexander Motin pp = cp->provider;
137700f32ecbSAlexander Motin buf = malloc(pp->sectorsize, M_MD_DDF, M_WAITOK | M_ZERO);
137800f32ecbSAlexander Motin error = g_write_data(cp, pp->mediasize - pp->sectorsize,
137900f32ecbSAlexander Motin buf, pp->sectorsize);
138000f32ecbSAlexander Motin if (error != 0) {
138100f32ecbSAlexander Motin G_RAID_DEBUG(1, "Cannot erase metadata on %s (error=%d).",
138200f32ecbSAlexander Motin pp->name, error);
138300f32ecbSAlexander Motin }
138400f32ecbSAlexander Motin free(buf, M_MD_DDF);
138500f32ecbSAlexander Motin return (error);
138600f32ecbSAlexander Motin }
138700f32ecbSAlexander Motin
138800f32ecbSAlexander Motin static struct g_raid_volume *
g_raid_md_ddf_get_volume(struct g_raid_softc * sc,uint8_t * GUID)138900f32ecbSAlexander Motin g_raid_md_ddf_get_volume(struct g_raid_softc *sc, uint8_t *GUID)
139000f32ecbSAlexander Motin {
139100f32ecbSAlexander Motin struct g_raid_volume *vol;
139200f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
139300f32ecbSAlexander Motin
139400f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
139500f32ecbSAlexander Motin pv = vol->v_md_data;
139600f32ecbSAlexander Motin if (memcmp(pv->pv_meta.vde->VD_GUID, GUID, 24) == 0)
139700f32ecbSAlexander Motin break;
139800f32ecbSAlexander Motin }
139900f32ecbSAlexander Motin return (vol);
140000f32ecbSAlexander Motin }
140100f32ecbSAlexander Motin
140200f32ecbSAlexander Motin static struct g_raid_disk *
g_raid_md_ddf_get_disk(struct g_raid_softc * sc,uint8_t * GUID,uint32_t id)140300f32ecbSAlexander Motin g_raid_md_ddf_get_disk(struct g_raid_softc *sc, uint8_t *GUID, uint32_t id)
140400f32ecbSAlexander Motin {
140500f32ecbSAlexander Motin struct g_raid_disk *disk;
140600f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
140700f32ecbSAlexander Motin struct ddf_meta *meta;
140800f32ecbSAlexander Motin
140900f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
141000f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
141100f32ecbSAlexander Motin meta = &pd->pd_meta;
141200f32ecbSAlexander Motin if (GUID != NULL) {
141300f32ecbSAlexander Motin if (memcmp(meta->pdd->PD_GUID, GUID, 24) == 0)
141400f32ecbSAlexander Motin break;
141500f32ecbSAlexander Motin } else {
141600f32ecbSAlexander Motin if (GET32(meta, pdd->PD_Reference) == id)
141700f32ecbSAlexander Motin break;
141800f32ecbSAlexander Motin }
141900f32ecbSAlexander Motin }
142000f32ecbSAlexander Motin return (disk);
142100f32ecbSAlexander Motin }
142200f32ecbSAlexander Motin
142300f32ecbSAlexander Motin static int
g_raid_md_ddf_purge_volumes(struct g_raid_softc * sc)142400f32ecbSAlexander Motin g_raid_md_ddf_purge_volumes(struct g_raid_softc *sc)
142500f32ecbSAlexander Motin {
142600f32ecbSAlexander Motin struct g_raid_volume *vol, *tvol;
142700f32ecbSAlexander Motin int i, res;
142800f32ecbSAlexander Motin
142900f32ecbSAlexander Motin res = 0;
143000f32ecbSAlexander Motin TAILQ_FOREACH_SAFE(vol, &sc->sc_volumes, v_next, tvol) {
143100f32ecbSAlexander Motin if (vol->v_stopping)
143200f32ecbSAlexander Motin continue;
143300f32ecbSAlexander Motin for (i = 0; i < vol->v_disks_count; i++) {
143400f32ecbSAlexander Motin if (vol->v_subdisks[i].sd_state != G_RAID_SUBDISK_S_NONE)
143500f32ecbSAlexander Motin break;
143600f32ecbSAlexander Motin }
143700f32ecbSAlexander Motin if (i >= vol->v_disks_count) {
143800f32ecbSAlexander Motin g_raid_destroy_volume(vol);
143900f32ecbSAlexander Motin res = 1;
144000f32ecbSAlexander Motin }
144100f32ecbSAlexander Motin }
144200f32ecbSAlexander Motin return (res);
144300f32ecbSAlexander Motin }
144400f32ecbSAlexander Motin
144500f32ecbSAlexander Motin static int
g_raid_md_ddf_purge_disks(struct g_raid_softc * sc)144600f32ecbSAlexander Motin g_raid_md_ddf_purge_disks(struct g_raid_softc *sc)
144700f32ecbSAlexander Motin {
144800f32ecbSAlexander Motin #if 0
144900f32ecbSAlexander Motin struct g_raid_disk *disk, *tdisk;
145000f32ecbSAlexander Motin struct g_raid_volume *vol;
145100f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
145200f32ecbSAlexander Motin int i, j, res;
145300f32ecbSAlexander Motin
145400f32ecbSAlexander Motin res = 0;
145500f32ecbSAlexander Motin TAILQ_FOREACH_SAFE(disk, &sc->sc_disks, d_next, tdisk) {
145600f32ecbSAlexander Motin if (disk->d_state == G_RAID_DISK_S_SPARE)
145700f32ecbSAlexander Motin continue;
145800f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
145900f32ecbSAlexander Motin
146000f32ecbSAlexander Motin /* Scan for deleted volumes. */
146100f32ecbSAlexander Motin for (i = 0; i < pd->pd_subdisks; ) {
146200f32ecbSAlexander Motin vol = g_raid_md_ddf_get_volume(sc,
146300f32ecbSAlexander Motin pd->pd_meta[i]->volume_id);
146400f32ecbSAlexander Motin if (vol != NULL && !vol->v_stopping) {
146500f32ecbSAlexander Motin i++;
146600f32ecbSAlexander Motin continue;
146700f32ecbSAlexander Motin }
146800f32ecbSAlexander Motin free(pd->pd_meta[i], M_MD_DDF);
146900f32ecbSAlexander Motin for (j = i; j < pd->pd_subdisks - 1; j++)
147000f32ecbSAlexander Motin pd->pd_meta[j] = pd->pd_meta[j + 1];
147100f32ecbSAlexander Motin pd->pd_meta[DDF_MAX_SUBDISKS - 1] = NULL;
147200f32ecbSAlexander Motin pd->pd_subdisks--;
147300f32ecbSAlexander Motin pd->pd_updated = 1;
147400f32ecbSAlexander Motin }
147500f32ecbSAlexander Motin
147600f32ecbSAlexander Motin /* If there is no metadata left - erase and delete disk. */
147700f32ecbSAlexander Motin if (pd->pd_subdisks == 0) {
147800f32ecbSAlexander Motin ddf_meta_erase(disk->d_consumer);
147900f32ecbSAlexander Motin g_raid_destroy_disk(disk);
148000f32ecbSAlexander Motin res = 1;
148100f32ecbSAlexander Motin }
148200f32ecbSAlexander Motin }
148300f32ecbSAlexander Motin return (res);
148400f32ecbSAlexander Motin #endif
148500f32ecbSAlexander Motin return (0);
148600f32ecbSAlexander Motin }
148700f32ecbSAlexander Motin
148800f32ecbSAlexander Motin static int
g_raid_md_ddf_supported(int level,int qual,int disks,int force)148900f32ecbSAlexander Motin g_raid_md_ddf_supported(int level, int qual, int disks, int force)
149000f32ecbSAlexander Motin {
149100f32ecbSAlexander Motin
149200f32ecbSAlexander Motin if (disks > DDF_MAX_DISKS_HARD)
149300f32ecbSAlexander Motin return (0);
149400f32ecbSAlexander Motin switch (level) {
149500f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID0:
149600f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_NONE)
149700f32ecbSAlexander Motin return (0);
149800f32ecbSAlexander Motin if (disks < 1)
149900f32ecbSAlexander Motin return (0);
150000f32ecbSAlexander Motin if (!force && disks < 2)
150100f32ecbSAlexander Motin return (0);
150200f32ecbSAlexander Motin break;
150300f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID1:
150400f32ecbSAlexander Motin if (disks < 1)
150500f32ecbSAlexander Motin return (0);
150600f32ecbSAlexander Motin if (qual == G_RAID_VOLUME_RLQ_R1SM) {
150700f32ecbSAlexander Motin if (!force && disks != 2)
150800f32ecbSAlexander Motin return (0);
150900f32ecbSAlexander Motin } else if (qual == G_RAID_VOLUME_RLQ_R1MM) {
151000f32ecbSAlexander Motin if (!force && disks != 3)
151100f32ecbSAlexander Motin return (0);
151200f32ecbSAlexander Motin } else
151300f32ecbSAlexander Motin return (0);
151400f32ecbSAlexander Motin break;
151500f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID3:
151600f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R3P0 &&
151700f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R3PN)
151800f32ecbSAlexander Motin return (0);
151900f32ecbSAlexander Motin if (disks < 3)
152000f32ecbSAlexander Motin return (0);
152100f32ecbSAlexander Motin break;
152200f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID4:
152300f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R4P0 &&
152400f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R4PN)
152500f32ecbSAlexander Motin return (0);
152600f32ecbSAlexander Motin if (disks < 3)
152700f32ecbSAlexander Motin return (0);
152800f32ecbSAlexander Motin break;
152900f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID5:
153000f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R5RA &&
153100f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5RS &&
153200f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5LA &&
153300f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5LS)
153400f32ecbSAlexander Motin return (0);
153500f32ecbSAlexander Motin if (disks < 3)
153600f32ecbSAlexander Motin return (0);
153700f32ecbSAlexander Motin break;
153800f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID6:
153900f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R6RA &&
154000f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R6RS &&
154100f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R6LA &&
154200f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R6LS)
154300f32ecbSAlexander Motin return (0);
154400f32ecbSAlexander Motin if (disks < 4)
154500f32ecbSAlexander Motin return (0);
154600f32ecbSAlexander Motin break;
154700f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAIDMDF:
154800f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_RMDFRA &&
154900f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_RMDFRS &&
155000f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_RMDFLA &&
155100f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_RMDFLS)
155200f32ecbSAlexander Motin return (0);
15538f12ca2eSAlexander Motin if (disks < 4)
155400f32ecbSAlexander Motin return (0);
155500f32ecbSAlexander Motin break;
155600f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID1E:
155700f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R1EA &&
155800f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R1EO)
155900f32ecbSAlexander Motin return (0);
15602b9c925fSAlexander Motin if (disks < 3)
156100f32ecbSAlexander Motin return (0);
156200f32ecbSAlexander Motin break;
156300f32ecbSAlexander Motin case G_RAID_VOLUME_RL_SINGLE:
156400f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_NONE)
156500f32ecbSAlexander Motin return (0);
156600f32ecbSAlexander Motin if (disks != 1)
156700f32ecbSAlexander Motin return (0);
156800f32ecbSAlexander Motin break;
156900f32ecbSAlexander Motin case G_RAID_VOLUME_RL_CONCAT:
157000f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_NONE)
157100f32ecbSAlexander Motin return (0);
157200f32ecbSAlexander Motin if (disks < 2)
157300f32ecbSAlexander Motin return (0);
157400f32ecbSAlexander Motin break;
157500f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID5E:
157600f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R5ERA &&
157700f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5ERS &&
157800f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5ELA &&
157900f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5ELS)
158000f32ecbSAlexander Motin return (0);
158100f32ecbSAlexander Motin if (disks < 4)
158200f32ecbSAlexander Motin return (0);
158300f32ecbSAlexander Motin break;
158400f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID5EE:
158500f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R5EERA &&
158600f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5EERS &&
158700f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5EELA &&
158800f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5EELS)
158900f32ecbSAlexander Motin return (0);
159000f32ecbSAlexander Motin if (disks < 4)
159100f32ecbSAlexander Motin return (0);
159200f32ecbSAlexander Motin break;
159300f32ecbSAlexander Motin case G_RAID_VOLUME_RL_RAID5R:
159400f32ecbSAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R5RRA &&
159500f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5RRS &&
159600f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5RLA &&
159700f32ecbSAlexander Motin qual != G_RAID_VOLUME_RLQ_R5RLS)
159800f32ecbSAlexander Motin return (0);
159900f32ecbSAlexander Motin if (disks < 3)
160000f32ecbSAlexander Motin return (0);
160100f32ecbSAlexander Motin break;
160200f32ecbSAlexander Motin default:
160300f32ecbSAlexander Motin return (0);
160400f32ecbSAlexander Motin }
160500f32ecbSAlexander Motin return (1);
160600f32ecbSAlexander Motin }
160700f32ecbSAlexander Motin
160800f32ecbSAlexander Motin static int
g_raid_md_ddf_start_disk(struct g_raid_disk * disk,struct g_raid_volume * vol)160900f32ecbSAlexander Motin g_raid_md_ddf_start_disk(struct g_raid_disk *disk, struct g_raid_volume *vol)
161000f32ecbSAlexander Motin {
161100f32ecbSAlexander Motin struct g_raid_softc *sc;
161200f32ecbSAlexander Motin struct g_raid_subdisk *sd;
161300f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
161400f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
161500f32ecbSAlexander Motin struct g_raid_md_ddf_object *mdi;
161600f32ecbSAlexander Motin struct ddf_vol_meta *vmeta;
161700f32ecbSAlexander Motin struct ddf_meta *pdmeta, *gmeta;
161800f32ecbSAlexander Motin struct ddf_vdc_record *vdc1;
1619d525d875SAlexander Motin struct ddf_sa_record *sa;
162000f32ecbSAlexander Motin off_t size, eoff = 0, esize = 0;
162100f32ecbSAlexander Motin uint64_t *val2;
162200f32ecbSAlexander Motin int disk_pos, md_disk_bvd = -1, md_disk_pos = -1, md_pde_pos;
162300f32ecbSAlexander Motin int i, resurrection = 0;
162400f32ecbSAlexander Motin uint32_t reference;
162500f32ecbSAlexander Motin
162600f32ecbSAlexander Motin sc = disk->d_softc;
162700f32ecbSAlexander Motin mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
162800f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
162900f32ecbSAlexander Motin pdmeta = &pd->pd_meta;
163000f32ecbSAlexander Motin reference = GET32(&pd->pd_meta, pdd->PD_Reference);
163100f32ecbSAlexander Motin
163200f32ecbSAlexander Motin pv = vol->v_md_data;
163300f32ecbSAlexander Motin vmeta = &pv->pv_meta;
163400f32ecbSAlexander Motin gmeta = &mdi->mdio_meta;
163500f32ecbSAlexander Motin
163628323addSBryan Drewery /* Find disk position in metadata by its reference. */
163700f32ecbSAlexander Motin disk_pos = ddf_meta_find_disk(vmeta, reference,
163800f32ecbSAlexander Motin &md_disk_bvd, &md_disk_pos);
163900f32ecbSAlexander Motin md_pde_pos = ddf_meta_find_pd(gmeta, NULL, reference);
164000f32ecbSAlexander Motin
164100f32ecbSAlexander Motin if (disk_pos < 0) {
1642d525d875SAlexander Motin G_RAID_DEBUG1(1, sc,
1643d525d875SAlexander Motin "Disk %s is not a present part of the volume %s",
164400f32ecbSAlexander Motin g_raid_get_diskname(disk), vol->v_name);
164500f32ecbSAlexander Motin
164600f32ecbSAlexander Motin /* Failed stale disk is useless for us. */
164700f32ecbSAlexander Motin if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) != 0) {
164800f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE_FAILED);
164900f32ecbSAlexander Motin return (0);
165000f32ecbSAlexander Motin }
165100f32ecbSAlexander Motin
165200f32ecbSAlexander Motin /* If disk has some metadata for this volume - erase. */
1653d525d875SAlexander Motin if ((vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL)
165400f32ecbSAlexander Motin SET32D(pdmeta, vdc1->Signature, 0xffffffff);
165500f32ecbSAlexander Motin
165600f32ecbSAlexander Motin /* If we are in the start process, that's all for now. */
165700f32ecbSAlexander Motin if (!pv->pv_started)
165800f32ecbSAlexander Motin goto nofit;
165900f32ecbSAlexander Motin /*
166000f32ecbSAlexander Motin * If we have already started - try to get use of the disk.
166100f32ecbSAlexander Motin * Try to replace OFFLINE disks first, then FAILED.
166200f32ecbSAlexander Motin */
166300f32ecbSAlexander Motin if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
166400f32ecbSAlexander Motin GET16(&pd->pd_meta, hdr->Max_Partitions)) {
166500f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "No free partitions on disk %s",
166600f32ecbSAlexander Motin g_raid_get_diskname(disk));
166700f32ecbSAlexander Motin goto nofit;
166800f32ecbSAlexander Motin }
166900f32ecbSAlexander Motin ddf_meta_unused_range(&pd->pd_meta, &eoff, &esize);
167000f32ecbSAlexander Motin if (esize == 0) {
167100f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "No free space on disk %s",
167200f32ecbSAlexander Motin g_raid_get_diskname(disk));
167300f32ecbSAlexander Motin goto nofit;
167400f32ecbSAlexander Motin }
167514f9f25bSAlexander Motin eoff *= pd->pd_meta.sectorsize;
167614f9f25bSAlexander Motin esize *= pd->pd_meta.sectorsize;
167700f32ecbSAlexander Motin size = INT64_MAX;
167800f32ecbSAlexander Motin for (i = 0; i < vol->v_disks_count; i++) {
167900f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
168000f32ecbSAlexander Motin if (sd->sd_state != G_RAID_SUBDISK_S_NONE)
168100f32ecbSAlexander Motin size = sd->sd_size;
168200f32ecbSAlexander Motin if (sd->sd_state <= G_RAID_SUBDISK_S_FAILED &&
168300f32ecbSAlexander Motin (disk_pos < 0 ||
168400f32ecbSAlexander Motin vol->v_subdisks[i].sd_state < sd->sd_state))
168500f32ecbSAlexander Motin disk_pos = i;
168600f32ecbSAlexander Motin }
168700f32ecbSAlexander Motin if (disk_pos >= 0 &&
168800f32ecbSAlexander Motin vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT &&
168914f9f25bSAlexander Motin esize < size) {
169000f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "Disk %s free space "
169100f32ecbSAlexander Motin "is too small (%ju < %ju)",
169214f9f25bSAlexander Motin g_raid_get_diskname(disk), esize, size);
169300f32ecbSAlexander Motin disk_pos = -1;
169400f32ecbSAlexander Motin }
169500f32ecbSAlexander Motin if (disk_pos >= 0) {
169600f32ecbSAlexander Motin if (vol->v_raid_level != G_RAID_VOLUME_RL_CONCAT)
169714f9f25bSAlexander Motin esize = size;
169800f32ecbSAlexander Motin md_disk_bvd = disk_pos / GET16(vmeta, vdc->Primary_Element_Count); // XXX
169900f32ecbSAlexander Motin md_disk_pos = disk_pos % GET16(vmeta, vdc->Primary_Element_Count); // XXX
170000f32ecbSAlexander Motin } else {
170100f32ecbSAlexander Motin nofit:
1702d525d875SAlexander Motin if (disk->d_state == G_RAID_DISK_S_NONE)
170300f32ecbSAlexander Motin g_raid_change_disk_state(disk,
1704d525d875SAlexander Motin G_RAID_DISK_S_STALE);
170500f32ecbSAlexander Motin return (0);
170600f32ecbSAlexander Motin }
1707d525d875SAlexander Motin
1708d525d875SAlexander Motin /*
1709d525d875SAlexander Motin * If spare is committable, delete spare record.
1710d525d875SAlexander Motin * Othersize, mark it active and leave there.
1711d525d875SAlexander Motin */
1712d525d875SAlexander Motin sa = ddf_meta_find_sa(&pd->pd_meta, 0);
1713d525d875SAlexander Motin if (sa != NULL) {
1714d525d875SAlexander Motin if ((GET8D(&pd->pd_meta, sa->Spare_Type) &
1715d525d875SAlexander Motin DDF_SAR_TYPE_REVERTIBLE) == 0) {
1716d525d875SAlexander Motin SET32D(&pd->pd_meta, sa->Signature, 0xffffffff);
1717d525d875SAlexander Motin } else {
1718d525d875SAlexander Motin SET8D(&pd->pd_meta, sa->Spare_Type,
1719d525d875SAlexander Motin GET8D(&pd->pd_meta, sa->Spare_Type) |
1720d525d875SAlexander Motin DDF_SAR_TYPE_ACTIVE);
1721d525d875SAlexander Motin }
1722d525d875SAlexander Motin }
1723d525d875SAlexander Motin
172400f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "Disk %s takes pos %d in the volume %s",
172500f32ecbSAlexander Motin g_raid_get_diskname(disk), disk_pos, vol->v_name);
172600f32ecbSAlexander Motin resurrection = 1;
172700f32ecbSAlexander Motin }
172800f32ecbSAlexander Motin
172900f32ecbSAlexander Motin sd = &vol->v_subdisks[disk_pos];
173000f32ecbSAlexander Motin
173100f32ecbSAlexander Motin if (resurrection && sd->sd_disk != NULL) {
173200f32ecbSAlexander Motin g_raid_change_disk_state(sd->sd_disk,
173300f32ecbSAlexander Motin G_RAID_DISK_S_STALE_FAILED);
173400f32ecbSAlexander Motin TAILQ_REMOVE(&sd->sd_disk->d_subdisks,
173500f32ecbSAlexander Motin sd, sd_next);
173600f32ecbSAlexander Motin }
173700f32ecbSAlexander Motin vol->v_subdisks[disk_pos].sd_disk = disk;
173800f32ecbSAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
173900f32ecbSAlexander Motin
174000f32ecbSAlexander Motin /* Welcome the new disk. */
174100f32ecbSAlexander Motin if (resurrection)
174200f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
17431229e83dSAlexander Motin else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA)
174400f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED);
174500f32ecbSAlexander Motin else
174600f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
174700f32ecbSAlexander Motin
174800f32ecbSAlexander Motin if (resurrection) {
174914f9f25bSAlexander Motin sd->sd_offset = eoff;
175014f9f25bSAlexander Motin sd->sd_size = esize;
175100f32ecbSAlexander Motin } else if (pdmeta->cr != NULL &&
175200f32ecbSAlexander Motin (vdc1 = ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID)) != NULL) {
175300f32ecbSAlexander Motin val2 = (uint64_t *)&(vdc1->Physical_Disk_Sequence[GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
175400f32ecbSAlexander Motin sd->sd_offset = (off_t)GET64P(pdmeta, val2 + md_disk_pos) * 512;
175500f32ecbSAlexander Motin sd->sd_size = (off_t)GET64D(pdmeta, vdc1->Block_Count) * 512;
175600f32ecbSAlexander Motin }
175700f32ecbSAlexander Motin
175800f32ecbSAlexander Motin if (resurrection) {
175900f32ecbSAlexander Motin /* Stale disk, almost same as new. */
176000f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
176100f32ecbSAlexander Motin G_RAID_SUBDISK_S_NEW);
17621229e83dSAlexander Motin } else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) {
176300f32ecbSAlexander Motin /* Failed disk. */
176400f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
176500f32ecbSAlexander Motin G_RAID_SUBDISK_S_FAILED);
17661229e83dSAlexander Motin } else if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) &
176700f32ecbSAlexander Motin (DDF_PDE_FAILED | DDF_PDE_REBUILD)) != 0) {
176800f32ecbSAlexander Motin /* Rebuilding disk. */
176900f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
177000f32ecbSAlexander Motin G_RAID_SUBDISK_S_REBUILD);
177100f32ecbSAlexander Motin sd->sd_rebuild_pos = 0;
177200f32ecbSAlexander Motin } else if ((GET8(vmeta, vde->VD_State) & DDF_VDE_DIRTY) != 0 ||
177300f32ecbSAlexander Motin (GET8(vmeta, vde->Init_State) & DDF_VDE_INIT_MASK) !=
177400f32ecbSAlexander Motin DDF_VDE_INIT_FULL) {
177500f32ecbSAlexander Motin /* Stale disk or dirty volume (unclean shutdown). */
177600f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
177700f32ecbSAlexander Motin G_RAID_SUBDISK_S_STALE);
177800f32ecbSAlexander Motin } else {
177900f32ecbSAlexander Motin /* Up to date disk. */
178000f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
178100f32ecbSAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
178200f32ecbSAlexander Motin }
178300f32ecbSAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
178400f32ecbSAlexander Motin G_RAID_EVENT_SUBDISK);
178500f32ecbSAlexander Motin
178600f32ecbSAlexander Motin return (resurrection);
178700f32ecbSAlexander Motin }
178800f32ecbSAlexander Motin
178900f32ecbSAlexander Motin static void
g_raid_md_ddf_refill(struct g_raid_softc * sc)179000f32ecbSAlexander Motin g_raid_md_ddf_refill(struct g_raid_softc *sc)
179100f32ecbSAlexander Motin {
179200f32ecbSAlexander Motin struct g_raid_volume *vol;
179300f32ecbSAlexander Motin struct g_raid_subdisk *sd;
179400f32ecbSAlexander Motin struct g_raid_disk *disk;
179500f32ecbSAlexander Motin struct g_raid_md_object *md;
179600f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
179700f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
179800f32ecbSAlexander Motin int update, updated, i, bad;
179900f32ecbSAlexander Motin
180000f32ecbSAlexander Motin md = sc->sc_md;
180100f32ecbSAlexander Motin restart:
180200f32ecbSAlexander Motin updated = 0;
180300f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
180400f32ecbSAlexander Motin pv = vol->v_md_data;
180500f32ecbSAlexander Motin if (!pv->pv_started || vol->v_stopping)
180600f32ecbSAlexander Motin continue;
180700f32ecbSAlexander Motin
180800f32ecbSAlexander Motin /* Search for subdisk that needs replacement. */
180900f32ecbSAlexander Motin bad = 0;
181000f32ecbSAlexander Motin for (i = 0; i < vol->v_disks_count; i++) {
181100f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
181200f32ecbSAlexander Motin if (sd->sd_state == G_RAID_SUBDISK_S_NONE ||
181300f32ecbSAlexander Motin sd->sd_state == G_RAID_SUBDISK_S_FAILED)
181400f32ecbSAlexander Motin bad = 1;
181500f32ecbSAlexander Motin }
181600f32ecbSAlexander Motin if (!bad)
181700f32ecbSAlexander Motin continue;
181800f32ecbSAlexander Motin
181900f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "Volume %s is not complete, "
182000f32ecbSAlexander Motin "trying to refill.", vol->v_name);
182100f32ecbSAlexander Motin
182200f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
182300f32ecbSAlexander Motin /* Skip failed. */
182400f32ecbSAlexander Motin if (disk->d_state < G_RAID_DISK_S_SPARE)
182500f32ecbSAlexander Motin continue;
182600f32ecbSAlexander Motin /* Skip already used by this volume. */
182700f32ecbSAlexander Motin for (i = 0; i < vol->v_disks_count; i++) {
182800f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
182900f32ecbSAlexander Motin if (sd->sd_disk == disk)
183000f32ecbSAlexander Motin break;
183100f32ecbSAlexander Motin }
183200f32ecbSAlexander Motin if (i < vol->v_disks_count)
183300f32ecbSAlexander Motin continue;
183400f32ecbSAlexander Motin
183500f32ecbSAlexander Motin /* Try to use disk if it has empty extents. */
183600f32ecbSAlexander Motin pd = disk->d_md_data;
183700f32ecbSAlexander Motin if (ddf_meta_count_vdc(&pd->pd_meta, NULL) <
183800f32ecbSAlexander Motin GET16(&pd->pd_meta, hdr->Max_Partitions)) {
183900f32ecbSAlexander Motin update = g_raid_md_ddf_start_disk(disk, vol);
184000f32ecbSAlexander Motin } else
184100f32ecbSAlexander Motin update = 0;
184200f32ecbSAlexander Motin if (update) {
184300f32ecbSAlexander Motin updated = 1;
184400f32ecbSAlexander Motin g_raid_md_write_ddf(md, vol, NULL, disk);
184500f32ecbSAlexander Motin break;
184600f32ecbSAlexander Motin }
184700f32ecbSAlexander Motin }
184800f32ecbSAlexander Motin }
184900f32ecbSAlexander Motin if (updated)
185000f32ecbSAlexander Motin goto restart;
185100f32ecbSAlexander Motin }
185200f32ecbSAlexander Motin
185300f32ecbSAlexander Motin static void
g_raid_md_ddf_start(struct g_raid_volume * vol)185400f32ecbSAlexander Motin g_raid_md_ddf_start(struct g_raid_volume *vol)
185500f32ecbSAlexander Motin {
185600f32ecbSAlexander Motin struct g_raid_softc *sc;
185700f32ecbSAlexander Motin struct g_raid_subdisk *sd;
185800f32ecbSAlexander Motin struct g_raid_disk *disk;
185900f32ecbSAlexander Motin struct g_raid_md_object *md;
1860d525d875SAlexander Motin struct g_raid_md_ddf_perdisk *pd;
186100f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
186247e98096SAlexander Motin struct g_raid_md_ddf_object *mdi;
186300f32ecbSAlexander Motin struct ddf_vol_meta *vmeta;
186400f32ecbSAlexander Motin uint64_t *val2;
186500f32ecbSAlexander Motin int i, j, bvd;
186600f32ecbSAlexander Motin
186700f32ecbSAlexander Motin sc = vol->v_softc;
186800f32ecbSAlexander Motin md = sc->sc_md;
186947e98096SAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
187000f32ecbSAlexander Motin pv = vol->v_md_data;
187100f32ecbSAlexander Motin vmeta = &pv->pv_meta;
187200f32ecbSAlexander Motin
187300f32ecbSAlexander Motin vol->v_raid_level = GET8(vmeta, vdc->Primary_RAID_Level);
187400f32ecbSAlexander Motin vol->v_raid_level_qualifier = GET8(vmeta, vdc->RLQ);
187500f32ecbSAlexander Motin if (GET8(vmeta, vdc->Secondary_Element_Count) > 1 &&
187600f32ecbSAlexander Motin vol->v_raid_level == G_RAID_VOLUME_RL_RAID1 &&
187700f32ecbSAlexander Motin GET8(vmeta, vdc->Secondary_RAID_Level) == 0)
187800f32ecbSAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E;
187900f32ecbSAlexander Motin vol->v_sectorsize = GET16(vmeta, vdc->Block_Size);
188000f32ecbSAlexander Motin if (vol->v_sectorsize == 0xffff)
188100f32ecbSAlexander Motin vol->v_sectorsize = vmeta->sectorsize;
188200f32ecbSAlexander Motin vol->v_strip_size = vol->v_sectorsize << GET8(vmeta, vdc->Stripe_Size);
188300f32ecbSAlexander Motin vol->v_disks_count = GET16(vmeta, vdc->Primary_Element_Count) *
188400f32ecbSAlexander Motin GET8(vmeta, vdc->Secondary_Element_Count);
18858f12ca2eSAlexander Motin vol->v_mdf_pdisks = GET8(vmeta, vdc->MDF_Parity_Disks);
18868f12ca2eSAlexander Motin vol->v_mdf_polynomial = GET16(vmeta, vdc->MDF_Parity_Generator_Polynomial);
18878f12ca2eSAlexander Motin vol->v_mdf_method = GET8(vmeta, vdc->MDF_Constant_Generation_Method);
18888f12ca2eSAlexander Motin if (GET8(vmeta, vdc->Rotate_Parity_count) > 31)
18898f12ca2eSAlexander Motin vol->v_rotate_parity = 1;
18908f12ca2eSAlexander Motin else
18918f12ca2eSAlexander Motin vol->v_rotate_parity = 1 << GET8(vmeta, vdc->Rotate_Parity_count);
189200f32ecbSAlexander Motin vol->v_mediasize = GET64(vmeta, vdc->VD_Size) * vol->v_sectorsize;
189300f32ecbSAlexander Motin for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) {
189400f32ecbSAlexander Motin if (j == GET16(vmeta, vdc->Primary_Element_Count)) {
189500f32ecbSAlexander Motin j = 0;
189600f32ecbSAlexander Motin bvd++;
189700f32ecbSAlexander Motin }
189800f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
189900f32ecbSAlexander Motin if (vmeta->bvdc[bvd] == NULL) {
190000f32ecbSAlexander Motin sd->sd_offset = 0;
190100f32ecbSAlexander Motin sd->sd_size = GET64(vmeta, vdc->Block_Count) *
190200f32ecbSAlexander Motin vol->v_sectorsize;
190300f32ecbSAlexander Motin continue;
190400f32ecbSAlexander Motin }
190500f32ecbSAlexander Motin val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
190600f32ecbSAlexander Motin GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
190700f32ecbSAlexander Motin sd->sd_offset = GET64P(vmeta, val2 + j) * vol->v_sectorsize;
190800f32ecbSAlexander Motin sd->sd_size = GET64(vmeta, bvdc[bvd]->Block_Count) *
190900f32ecbSAlexander Motin vol->v_sectorsize;
191000f32ecbSAlexander Motin }
191100f32ecbSAlexander Motin g_raid_start_volume(vol);
191200f32ecbSAlexander Motin
191300f32ecbSAlexander Motin /* Make all disks found till the moment take their places. */
1914d525d875SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
1915d525d875SAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
1916d525d875SAlexander Motin if (ddf_meta_find_vdc(&pd->pd_meta, vmeta->vdc->VD_GUID) != NULL)
191700f32ecbSAlexander Motin g_raid_md_ddf_start_disk(disk, vol);
191800f32ecbSAlexander Motin }
191900f32ecbSAlexander Motin
192000f32ecbSAlexander Motin pv->pv_started = 1;
192147e98096SAlexander Motin mdi->mdio_starting--;
192200f32ecbSAlexander Motin callout_stop(&pv->pv_start_co);
192300f32ecbSAlexander Motin G_RAID_DEBUG1(0, sc, "Volume started.");
192400f32ecbSAlexander Motin g_raid_md_write_ddf(md, vol, NULL, NULL);
192500f32ecbSAlexander Motin
192600f32ecbSAlexander Motin /* Pickup any STALE/SPARE disks to refill array if needed. */
192700f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
192800f32ecbSAlexander Motin
192900f32ecbSAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_START, G_RAID_EVENT_VOLUME);
193000f32ecbSAlexander Motin }
193100f32ecbSAlexander Motin
193200f32ecbSAlexander Motin static void
g_raid_ddf_go(void * arg)193300f32ecbSAlexander Motin g_raid_ddf_go(void *arg)
193400f32ecbSAlexander Motin {
193500f32ecbSAlexander Motin struct g_raid_volume *vol;
193600f32ecbSAlexander Motin struct g_raid_softc *sc;
193700f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
193800f32ecbSAlexander Motin
193900f32ecbSAlexander Motin vol = arg;
194000f32ecbSAlexander Motin pv = vol->v_md_data;
194100f32ecbSAlexander Motin sc = vol->v_softc;
194200f32ecbSAlexander Motin if (!pv->pv_started) {
194300f32ecbSAlexander Motin G_RAID_DEBUG1(0, sc, "Force volume start due to timeout.");
194400f32ecbSAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_STARTMD,
194500f32ecbSAlexander Motin G_RAID_EVENT_VOLUME);
194600f32ecbSAlexander Motin }
194700f32ecbSAlexander Motin }
194800f32ecbSAlexander Motin
194900f32ecbSAlexander Motin static void
g_raid_md_ddf_new_disk(struct g_raid_disk * disk)195000f32ecbSAlexander Motin g_raid_md_ddf_new_disk(struct g_raid_disk *disk)
195100f32ecbSAlexander Motin {
195200f32ecbSAlexander Motin struct g_raid_softc *sc;
195300f32ecbSAlexander Motin struct g_raid_md_object *md;
195400f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
195500f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
195600f32ecbSAlexander Motin struct g_raid_md_ddf_object *mdi;
195700f32ecbSAlexander Motin struct g_raid_volume *vol;
195800f32ecbSAlexander Motin struct ddf_meta *pdmeta;
195900f32ecbSAlexander Motin struct ddf_vol_meta *vmeta;
196000f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
196100f32ecbSAlexander Motin struct ddf_vd_entry *vde;
1962d525d875SAlexander Motin int i, j, k, num, have, need, cnt, spare;
196300f32ecbSAlexander Motin uint32_t val;
196400f32ecbSAlexander Motin char buf[17];
196500f32ecbSAlexander Motin
196600f32ecbSAlexander Motin sc = disk->d_softc;
196700f32ecbSAlexander Motin md = sc->sc_md;
196800f32ecbSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
196900f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
197000f32ecbSAlexander Motin pdmeta = &pd->pd_meta;
197100f32ecbSAlexander Motin spare = -1;
197200f32ecbSAlexander Motin
197300f32ecbSAlexander Motin if (mdi->mdio_meta.hdr == NULL)
197400f32ecbSAlexander Motin ddf_meta_copy(&mdi->mdio_meta, pdmeta);
197500f32ecbSAlexander Motin else
197600f32ecbSAlexander Motin ddf_meta_update(&mdi->mdio_meta, pdmeta);
197700f32ecbSAlexander Motin
19782b9c925fSAlexander Motin num = GETCRNUM(pdmeta);
197900f32ecbSAlexander Motin for (j = 0; j < num; j++) {
19802b9c925fSAlexander Motin vdc = GETVDCPTR(pdmeta, j);
198100f32ecbSAlexander Motin val = GET32D(pdmeta, vdc->Signature);
198200f32ecbSAlexander Motin
198300f32ecbSAlexander Motin if (val == DDF_SA_SIGNATURE && spare == -1)
198400f32ecbSAlexander Motin spare = 1;
198500f32ecbSAlexander Motin
198600f32ecbSAlexander Motin if (val != DDF_VDCR_SIGNATURE)
198700f32ecbSAlexander Motin continue;
198800f32ecbSAlexander Motin spare = 0;
198900f32ecbSAlexander Motin k = ddf_meta_find_vd(pdmeta, vdc->VD_GUID);
199000f32ecbSAlexander Motin if (k < 0)
199100f32ecbSAlexander Motin continue;
199200f32ecbSAlexander Motin vde = &pdmeta->vdr->entry[k];
199300f32ecbSAlexander Motin
199400f32ecbSAlexander Motin /* Look for volume with matching ID. */
199500f32ecbSAlexander Motin vol = g_raid_md_ddf_get_volume(sc, vdc->VD_GUID);
199600f32ecbSAlexander Motin if (vol == NULL) {
199700f32ecbSAlexander Motin ddf_meta_get_name(pdmeta, k, buf);
199800f32ecbSAlexander Motin vol = g_raid_create_volume(sc, buf,
199900f32ecbSAlexander Motin GET16D(pdmeta, vde->VD_Number));
200000f32ecbSAlexander Motin pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
200100f32ecbSAlexander Motin vol->v_md_data = pv;
200200f32ecbSAlexander Motin callout_init(&pv->pv_start_co, 1);
200300f32ecbSAlexander Motin callout_reset(&pv->pv_start_co,
200400f32ecbSAlexander Motin g_raid_start_timeout * hz,
200500f32ecbSAlexander Motin g_raid_ddf_go, vol);
200647e98096SAlexander Motin mdi->mdio_starting++;
200700f32ecbSAlexander Motin } else
200800f32ecbSAlexander Motin pv = vol->v_md_data;
200900f32ecbSAlexander Motin
201000f32ecbSAlexander Motin /* If we haven't started yet - check metadata freshness. */
201100f32ecbSAlexander Motin vmeta = &pv->pv_meta;
201247e98096SAlexander Motin ddf_vol_meta_update(vmeta, pdmeta, vdc->VD_GUID, pv->pv_started);
201300f32ecbSAlexander Motin }
201400f32ecbSAlexander Motin
201500f32ecbSAlexander Motin if (spare == 1) {
201600f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
201700f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
201800f32ecbSAlexander Motin }
201900f32ecbSAlexander Motin
202000f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
202100f32ecbSAlexander Motin pv = vol->v_md_data;
202200f32ecbSAlexander Motin vmeta = &pv->pv_meta;
202300f32ecbSAlexander Motin
2024d525d875SAlexander Motin if (ddf_meta_find_vdc(pdmeta, vmeta->vdc->VD_GUID) == NULL)
2025d525d875SAlexander Motin continue;
2026d525d875SAlexander Motin
2027d525d875SAlexander Motin if (pv->pv_started) {
2028d525d875SAlexander Motin if (g_raid_md_ddf_start_disk(disk, vol))
2029d525d875SAlexander Motin g_raid_md_write_ddf(md, vol, NULL, NULL);
2030d525d875SAlexander Motin continue;
2031d525d875SAlexander Motin }
2032d525d875SAlexander Motin
203300f32ecbSAlexander Motin /* If we collected all needed disks - start array. */
203400f32ecbSAlexander Motin need = 0;
203500f32ecbSAlexander Motin have = 0;
203600f32ecbSAlexander Motin for (k = 0; k < GET8(vmeta, vdc->Secondary_Element_Count); k++) {
203700f32ecbSAlexander Motin if (vmeta->bvdc[k] == NULL) {
203800f32ecbSAlexander Motin need += GET16(vmeta, vdc->Primary_Element_Count);
203900f32ecbSAlexander Motin continue;
204000f32ecbSAlexander Motin }
204100f32ecbSAlexander Motin cnt = GET16(vmeta, bvdc[k]->Primary_Element_Count);
204200f32ecbSAlexander Motin need += cnt;
204300f32ecbSAlexander Motin for (i = 0; i < cnt; i++) {
204400f32ecbSAlexander Motin val = GET32(vmeta, bvdc[k]->Physical_Disk_Sequence[i]);
2045d525d875SAlexander Motin if (g_raid_md_ddf_get_disk(sc, NULL, val) != NULL)
204600f32ecbSAlexander Motin have++;
204700f32ecbSAlexander Motin }
204800f32ecbSAlexander Motin }
204900f32ecbSAlexander Motin G_RAID_DEBUG1(1, sc, "Volume %s now has %d of %d disks",
2050d525d875SAlexander Motin vol->v_name, have, need);
2051d525d875SAlexander Motin if (have == need)
205200f32ecbSAlexander Motin g_raid_md_ddf_start(vol);
205300f32ecbSAlexander Motin }
205400f32ecbSAlexander Motin }
205500f32ecbSAlexander Motin
205600f32ecbSAlexander Motin static int
g_raid_md_create_req_ddf(struct g_raid_md_object * md,struct g_class * mp,struct gctl_req * req,struct g_geom ** gp)20578df8e26aSAlexander Motin g_raid_md_create_req_ddf(struct g_raid_md_object *md, struct g_class *mp,
20588df8e26aSAlexander Motin struct gctl_req *req, struct g_geom **gp)
205900f32ecbSAlexander Motin {
206000f32ecbSAlexander Motin struct g_geom *geom;
206100f32ecbSAlexander Motin struct g_raid_softc *sc;
20628df8e26aSAlexander Motin struct g_raid_md_ddf_object *mdi, *mdi1;
20638df8e26aSAlexander Motin char name[16];
20648df8e26aSAlexander Motin const char *fmtopt;
20658df8e26aSAlexander Motin int be = 1;
20668df8e26aSAlexander Motin
20678df8e26aSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
20688df8e26aSAlexander Motin fmtopt = gctl_get_asciiparam(req, "fmtopt");
20698df8e26aSAlexander Motin if (fmtopt == NULL || strcasecmp(fmtopt, "BE") == 0)
20708df8e26aSAlexander Motin be = 1;
20718df8e26aSAlexander Motin else if (strcasecmp(fmtopt, "LE") == 0)
20728df8e26aSAlexander Motin be = 0;
20738df8e26aSAlexander Motin else {
20748df8e26aSAlexander Motin gctl_error(req, "Incorrect fmtopt argument.");
20758df8e26aSAlexander Motin return (G_RAID_MD_TASTE_FAIL);
20768df8e26aSAlexander Motin }
207700f32ecbSAlexander Motin
207800f32ecbSAlexander Motin /* Search for existing node. */
207900f32ecbSAlexander Motin LIST_FOREACH(geom, &mp->geom, geom) {
208000f32ecbSAlexander Motin sc = geom->softc;
208100f32ecbSAlexander Motin if (sc == NULL)
208200f32ecbSAlexander Motin continue;
208300f32ecbSAlexander Motin if (sc->sc_stopping != 0)
208400f32ecbSAlexander Motin continue;
208500f32ecbSAlexander Motin if (sc->sc_md->mdo_class != md->mdo_class)
208600f32ecbSAlexander Motin continue;
20878df8e26aSAlexander Motin mdi1 = (struct g_raid_md_ddf_object *)sc->sc_md;
20888df8e26aSAlexander Motin if (mdi1->mdio_bigendian != be)
20898df8e26aSAlexander Motin continue;
209000f32ecbSAlexander Motin break;
209100f32ecbSAlexander Motin }
209200f32ecbSAlexander Motin if (geom != NULL) {
209300f32ecbSAlexander Motin *gp = geom;
209400f32ecbSAlexander Motin return (G_RAID_MD_TASTE_EXISTING);
209500f32ecbSAlexander Motin }
209600f32ecbSAlexander Motin
209700f32ecbSAlexander Motin /* Create new one if not found. */
20988df8e26aSAlexander Motin mdi->mdio_bigendian = be;
20998df8e26aSAlexander Motin snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
21008df8e26aSAlexander Motin sc = g_raid_create_node(mp, name, md);
210100f32ecbSAlexander Motin if (sc == NULL)
210200f32ecbSAlexander Motin return (G_RAID_MD_TASTE_FAIL);
210300f32ecbSAlexander Motin md->mdo_softc = sc;
210400f32ecbSAlexander Motin *gp = sc->sc_geom;
210500f32ecbSAlexander Motin return (G_RAID_MD_TASTE_NEW);
210600f32ecbSAlexander Motin }
210700f32ecbSAlexander Motin
210800f32ecbSAlexander Motin static int
g_raid_md_taste_ddf(struct g_raid_md_object * md,struct g_class * mp,struct g_consumer * cp,struct g_geom ** gp)210900f32ecbSAlexander Motin g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
211000f32ecbSAlexander Motin struct g_consumer *cp, struct g_geom **gp)
211100f32ecbSAlexander Motin {
211200f32ecbSAlexander Motin struct g_consumer *rcp;
211300f32ecbSAlexander Motin struct g_provider *pp;
211400f32ecbSAlexander Motin struct g_raid_softc *sc;
211500f32ecbSAlexander Motin struct g_raid_disk *disk;
211600f32ecbSAlexander Motin struct ddf_meta meta;
211700f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
21188df8e26aSAlexander Motin struct g_raid_md_ddf_object *mdi;
211900f32ecbSAlexander Motin struct g_geom *geom;
2120609a7474SAlexander Motin int error, result, be;
212100f32ecbSAlexander Motin char name[16];
212200f32ecbSAlexander Motin
212300f32ecbSAlexander Motin G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name);
21248df8e26aSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
212500f32ecbSAlexander Motin pp = cp->provider;
212600f32ecbSAlexander Motin
212700f32ecbSAlexander Motin /* Read metadata from device. */
212800f32ecbSAlexander Motin g_topology_unlock();
212900f32ecbSAlexander Motin bzero(&meta, sizeof(meta));
213000f32ecbSAlexander Motin error = ddf_meta_read(cp, &meta);
213100f32ecbSAlexander Motin g_topology_lock();
213200f32ecbSAlexander Motin if (error != 0)
213300f32ecbSAlexander Motin return (G_RAID_MD_TASTE_FAIL);
21348df8e26aSAlexander Motin be = meta.bigendian;
213500f32ecbSAlexander Motin
213600f32ecbSAlexander Motin /* Metadata valid. Print it. */
213700f32ecbSAlexander Motin g_raid_md_ddf_print(&meta);
213800f32ecbSAlexander Motin
213900f32ecbSAlexander Motin /* Search for matching node. */
214000f32ecbSAlexander Motin sc = NULL;
214100f32ecbSAlexander Motin LIST_FOREACH(geom, &mp->geom, geom) {
214200f32ecbSAlexander Motin sc = geom->softc;
214300f32ecbSAlexander Motin if (sc == NULL)
214400f32ecbSAlexander Motin continue;
214500f32ecbSAlexander Motin if (sc->sc_stopping != 0)
214600f32ecbSAlexander Motin continue;
214700f32ecbSAlexander Motin if (sc->sc_md->mdo_class != md->mdo_class)
214800f32ecbSAlexander Motin continue;
21498df8e26aSAlexander Motin mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
21508df8e26aSAlexander Motin if (mdi->mdio_bigendian != be)
21518df8e26aSAlexander Motin continue;
215200f32ecbSAlexander Motin break;
215300f32ecbSAlexander Motin }
215400f32ecbSAlexander Motin
215500f32ecbSAlexander Motin /* Found matching node. */
215600f32ecbSAlexander Motin if (geom != NULL) {
215700f32ecbSAlexander Motin G_RAID_DEBUG(1, "Found matching array %s", sc->sc_name);
215800f32ecbSAlexander Motin result = G_RAID_MD_TASTE_EXISTING;
215900f32ecbSAlexander Motin
216000f32ecbSAlexander Motin } else { /* Not found matching node -- create one. */
216100f32ecbSAlexander Motin result = G_RAID_MD_TASTE_NEW;
21628df8e26aSAlexander Motin mdi->mdio_bigendian = be;
21638df8e26aSAlexander Motin snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
216400f32ecbSAlexander Motin sc = g_raid_create_node(mp, name, md);
216500f32ecbSAlexander Motin md->mdo_softc = sc;
216600f32ecbSAlexander Motin geom = sc->sc_geom;
216700f32ecbSAlexander Motin }
216800f32ecbSAlexander Motin
2169dea1e226SAlexander Motin /* There is no return after this point, so we close passed consumer. */
2170dea1e226SAlexander Motin g_access(cp, -1, 0, 0);
2171dea1e226SAlexander Motin
217200f32ecbSAlexander Motin rcp = g_new_consumer(geom);
217340ea77a0SAlexander Motin rcp->flags |= G_CF_DIRECT_RECEIVE;
217400f32ecbSAlexander Motin g_attach(rcp, pp);
217500f32ecbSAlexander Motin if (g_access(rcp, 1, 1, 1) != 0)
217600f32ecbSAlexander Motin ; //goto fail1;
217700f32ecbSAlexander Motin
217800f32ecbSAlexander Motin g_topology_unlock();
217900f32ecbSAlexander Motin sx_xlock(&sc->sc_lock);
218000f32ecbSAlexander Motin
218100f32ecbSAlexander Motin pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
218200f32ecbSAlexander Motin pd->pd_meta = meta;
218300f32ecbSAlexander Motin disk = g_raid_create_disk(sc);
218400f32ecbSAlexander Motin disk->d_md_data = (void *)pd;
218500f32ecbSAlexander Motin disk->d_consumer = rcp;
218600f32ecbSAlexander Motin rcp->private = disk;
218700f32ecbSAlexander Motin
2188609a7474SAlexander Motin g_raid_get_disk_info(disk);
218900f32ecbSAlexander Motin
219000f32ecbSAlexander Motin g_raid_md_ddf_new_disk(disk);
219100f32ecbSAlexander Motin
219200f32ecbSAlexander Motin sx_xunlock(&sc->sc_lock);
219300f32ecbSAlexander Motin g_topology_lock();
219400f32ecbSAlexander Motin *gp = geom;
219500f32ecbSAlexander Motin return (result);
219600f32ecbSAlexander Motin }
219700f32ecbSAlexander Motin
219800f32ecbSAlexander Motin static int
g_raid_md_event_ddf(struct g_raid_md_object * md,struct g_raid_disk * disk,u_int event)219900f32ecbSAlexander Motin g_raid_md_event_ddf(struct g_raid_md_object *md,
220000f32ecbSAlexander Motin struct g_raid_disk *disk, u_int event)
220100f32ecbSAlexander Motin {
220200f32ecbSAlexander Motin struct g_raid_softc *sc;
220300f32ecbSAlexander Motin
220400f32ecbSAlexander Motin sc = md->mdo_softc;
220500f32ecbSAlexander Motin if (disk == NULL)
220600f32ecbSAlexander Motin return (-1);
220700f32ecbSAlexander Motin switch (event) {
220800f32ecbSAlexander Motin case G_RAID_DISK_E_DISCONNECTED:
220900f32ecbSAlexander Motin /* Delete disk. */
221000f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE);
221100f32ecbSAlexander Motin g_raid_destroy_disk(disk);
221200f32ecbSAlexander Motin g_raid_md_ddf_purge_volumes(sc);
221300f32ecbSAlexander Motin
221400f32ecbSAlexander Motin /* Write updated metadata to all disks. */
221500f32ecbSAlexander Motin g_raid_md_write_ddf(md, NULL, NULL, NULL);
221600f32ecbSAlexander Motin
221700f32ecbSAlexander Motin /* Check if anything left. */
221800f32ecbSAlexander Motin if (g_raid_ndisks(sc, -1) == 0)
221900f32ecbSAlexander Motin g_raid_destroy_node(sc, 0);
222000f32ecbSAlexander Motin else
222100f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
222200f32ecbSAlexander Motin return (0);
222300f32ecbSAlexander Motin }
222400f32ecbSAlexander Motin return (-2);
222500f32ecbSAlexander Motin }
222600f32ecbSAlexander Motin
222700f32ecbSAlexander Motin static int
g_raid_md_volume_event_ddf(struct g_raid_md_object * md,struct g_raid_volume * vol,u_int event)222800f32ecbSAlexander Motin g_raid_md_volume_event_ddf(struct g_raid_md_object *md,
222900f32ecbSAlexander Motin struct g_raid_volume *vol, u_int event)
223000f32ecbSAlexander Motin {
223100f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
223200f32ecbSAlexander Motin
223300f32ecbSAlexander Motin pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
223400f32ecbSAlexander Motin switch (event) {
223500f32ecbSAlexander Motin case G_RAID_VOLUME_E_STARTMD:
223600f32ecbSAlexander Motin if (!pv->pv_started)
223700f32ecbSAlexander Motin g_raid_md_ddf_start(vol);
223800f32ecbSAlexander Motin return (0);
223900f32ecbSAlexander Motin }
224000f32ecbSAlexander Motin return (-2);
224100f32ecbSAlexander Motin }
224200f32ecbSAlexander Motin
224300f32ecbSAlexander Motin static int
g_raid_md_ctl_ddf(struct g_raid_md_object * md,struct gctl_req * req)224400f32ecbSAlexander Motin g_raid_md_ctl_ddf(struct g_raid_md_object *md,
224500f32ecbSAlexander Motin struct gctl_req *req)
224600f32ecbSAlexander Motin {
224700f32ecbSAlexander Motin struct g_raid_softc *sc;
224800f32ecbSAlexander Motin struct g_raid_volume *vol, *vol1;
224900f32ecbSAlexander Motin struct g_raid_subdisk *sd;
225000f32ecbSAlexander Motin struct g_raid_disk *disk, *disks[DDF_MAX_DISKS_HARD];
225100f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
225200f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
225300f32ecbSAlexander Motin struct g_raid_md_ddf_object *mdi;
2254d525d875SAlexander Motin struct ddf_sa_record *sa;
225500f32ecbSAlexander Motin struct g_consumer *cp;
225600f32ecbSAlexander Motin struct g_provider *pp;
225700f32ecbSAlexander Motin char arg[16];
22586871a543SAlexander Motin const char *nodename, *verb, *volname, *levelname, *diskname;
225900f32ecbSAlexander Motin char *tmp;
226000f32ecbSAlexander Motin int *nargs, *force;
226100f32ecbSAlexander Motin off_t size, sectorsize, strip, offs[DDF_MAX_DISKS_HARD], esize;
226200f32ecbSAlexander Motin intmax_t *sizearg, *striparg;
226300f32ecbSAlexander Motin int i, numdisks, len, level, qual;
226400f32ecbSAlexander Motin int error;
226500f32ecbSAlexander Motin
226600f32ecbSAlexander Motin sc = md->mdo_softc;
226700f32ecbSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
226800f32ecbSAlexander Motin verb = gctl_get_param(req, "verb", NULL);
226900f32ecbSAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
227000f32ecbSAlexander Motin error = 0;
227100f32ecbSAlexander Motin
227200f32ecbSAlexander Motin if (strcmp(verb, "label") == 0) {
227300f32ecbSAlexander Motin if (*nargs < 4) {
227400f32ecbSAlexander Motin gctl_error(req, "Invalid number of arguments.");
227500f32ecbSAlexander Motin return (-1);
227600f32ecbSAlexander Motin }
227700f32ecbSAlexander Motin volname = gctl_get_asciiparam(req, "arg1");
227800f32ecbSAlexander Motin if (volname == NULL) {
227900f32ecbSAlexander Motin gctl_error(req, "No volume name.");
228000f32ecbSAlexander Motin return (-2);
228100f32ecbSAlexander Motin }
228200f32ecbSAlexander Motin levelname = gctl_get_asciiparam(req, "arg2");
228300f32ecbSAlexander Motin if (levelname == NULL) {
228400f32ecbSAlexander Motin gctl_error(req, "No RAID level.");
228500f32ecbSAlexander Motin return (-3);
228600f32ecbSAlexander Motin }
228700f32ecbSAlexander Motin if (g_raid_volume_str2level(levelname, &level, &qual)) {
228800f32ecbSAlexander Motin gctl_error(req, "Unknown RAID level '%s'.", levelname);
228900f32ecbSAlexander Motin return (-4);
229000f32ecbSAlexander Motin }
229100f32ecbSAlexander Motin numdisks = *nargs - 3;
229200f32ecbSAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
229300f32ecbSAlexander Motin if (!g_raid_md_ddf_supported(level, qual, numdisks,
229400f32ecbSAlexander Motin force ? *force : 0)) {
229500f32ecbSAlexander Motin gctl_error(req, "Unsupported RAID level "
229600f32ecbSAlexander Motin "(0x%02x/0x%02x), or number of disks (%d).",
229700f32ecbSAlexander Motin level, qual, numdisks);
229800f32ecbSAlexander Motin return (-5);
229900f32ecbSAlexander Motin }
230000f32ecbSAlexander Motin
230100f32ecbSAlexander Motin /* Search for disks, connect them and probe. */
230200f32ecbSAlexander Motin size = INT64_MAX;
230300f32ecbSAlexander Motin sectorsize = 0;
230400f32ecbSAlexander Motin bzero(disks, sizeof(disks));
230500f32ecbSAlexander Motin bzero(offs, sizeof(offs));
230600f32ecbSAlexander Motin for (i = 0; i < numdisks; i++) {
230700f32ecbSAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i + 3);
230800f32ecbSAlexander Motin diskname = gctl_get_asciiparam(req, arg);
230900f32ecbSAlexander Motin if (diskname == NULL) {
231000f32ecbSAlexander Motin gctl_error(req, "No disk name (%s).", arg);
231100f32ecbSAlexander Motin error = -6;
231200f32ecbSAlexander Motin break;
231300f32ecbSAlexander Motin }
231400f32ecbSAlexander Motin if (strcmp(diskname, "NONE") == 0)
231500f32ecbSAlexander Motin continue;
231600f32ecbSAlexander Motin
231700f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
231800f32ecbSAlexander Motin if (disk->d_consumer != NULL &&
231900f32ecbSAlexander Motin disk->d_consumer->provider != NULL &&
232000f32ecbSAlexander Motin strcmp(disk->d_consumer->provider->name,
232100f32ecbSAlexander Motin diskname) == 0)
232200f32ecbSAlexander Motin break;
232300f32ecbSAlexander Motin }
232400f32ecbSAlexander Motin if (disk != NULL) {
232500f32ecbSAlexander Motin if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
232600f32ecbSAlexander Motin gctl_error(req, "Disk '%s' is in a "
232700f32ecbSAlexander Motin "wrong state (%s).", diskname,
232800f32ecbSAlexander Motin g_raid_disk_state2str(disk->d_state));
232900f32ecbSAlexander Motin error = -7;
233000f32ecbSAlexander Motin break;
233100f32ecbSAlexander Motin }
233200f32ecbSAlexander Motin pd = disk->d_md_data;
233300f32ecbSAlexander Motin if (ddf_meta_count_vdc(&pd->pd_meta, NULL) >=
233400f32ecbSAlexander Motin GET16(&pd->pd_meta, hdr->Max_Partitions)) {
233500f32ecbSAlexander Motin gctl_error(req, "No free partitions "
233600f32ecbSAlexander Motin "on disk '%s'.",
233700f32ecbSAlexander Motin diskname);
233800f32ecbSAlexander Motin error = -7;
233900f32ecbSAlexander Motin break;
234000f32ecbSAlexander Motin }
234100f32ecbSAlexander Motin pp = disk->d_consumer->provider;
234200f32ecbSAlexander Motin disks[i] = disk;
234300f32ecbSAlexander Motin ddf_meta_unused_range(&pd->pd_meta,
234400f32ecbSAlexander Motin &offs[i], &esize);
234514f9f25bSAlexander Motin offs[i] *= pp->sectorsize;
234600f32ecbSAlexander Motin size = MIN(size, (off_t)esize * pp->sectorsize);
234700f32ecbSAlexander Motin sectorsize = MAX(sectorsize, pp->sectorsize);
234800f32ecbSAlexander Motin continue;
234900f32ecbSAlexander Motin }
235000f32ecbSAlexander Motin
235100f32ecbSAlexander Motin g_topology_lock();
235200f32ecbSAlexander Motin cp = g_raid_open_consumer(sc, diskname);
235300f32ecbSAlexander Motin if (cp == NULL) {
235400f32ecbSAlexander Motin gctl_error(req, "Can't open disk '%s'.",
235500f32ecbSAlexander Motin diskname);
235600f32ecbSAlexander Motin g_topology_unlock();
235700f32ecbSAlexander Motin error = -8;
235800f32ecbSAlexander Motin break;
235900f32ecbSAlexander Motin }
236000f32ecbSAlexander Motin pp = cp->provider;
236100f32ecbSAlexander Motin pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
236200f32ecbSAlexander Motin disk = g_raid_create_disk(sc);
236300f32ecbSAlexander Motin disk->d_md_data = (void *)pd;
236400f32ecbSAlexander Motin disk->d_consumer = cp;
236500f32ecbSAlexander Motin disks[i] = disk;
236600f32ecbSAlexander Motin cp->private = disk;
236700f32ecbSAlexander Motin ddf_meta_create(disk, &mdi->mdio_meta);
236800f32ecbSAlexander Motin if (mdi->mdio_meta.hdr == NULL)
236900f32ecbSAlexander Motin ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
237000f32ecbSAlexander Motin else
237100f32ecbSAlexander Motin ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
237200f32ecbSAlexander Motin g_topology_unlock();
237300f32ecbSAlexander Motin
2374609a7474SAlexander Motin g_raid_get_disk_info(disk);
237500f32ecbSAlexander Motin
237600f32ecbSAlexander Motin /* Reserve some space for metadata. */
237714f9f25bSAlexander Motin size = MIN(size, GET64(&pd->pd_meta,
237814f9f25bSAlexander Motin pdr->entry[0].Configured_Size) * pp->sectorsize);
237900f32ecbSAlexander Motin sectorsize = MAX(sectorsize, pp->sectorsize);
238000f32ecbSAlexander Motin }
238100f32ecbSAlexander Motin if (error != 0) {
238200f32ecbSAlexander Motin for (i = 0; i < numdisks; i++) {
238300f32ecbSAlexander Motin if (disks[i] != NULL &&
238400f32ecbSAlexander Motin disks[i]->d_state == G_RAID_DISK_S_NONE)
238500f32ecbSAlexander Motin g_raid_destroy_disk(disks[i]);
238600f32ecbSAlexander Motin }
238700f32ecbSAlexander Motin return (error);
238800f32ecbSAlexander Motin }
238900f32ecbSAlexander Motin
239000f32ecbSAlexander Motin if (sectorsize <= 0) {
239100f32ecbSAlexander Motin gctl_error(req, "Can't get sector size.");
239200f32ecbSAlexander Motin return (-8);
239300f32ecbSAlexander Motin }
239400f32ecbSAlexander Motin
239500f32ecbSAlexander Motin /* Handle size argument. */
239600f32ecbSAlexander Motin len = sizeof(*sizearg);
239700f32ecbSAlexander Motin sizearg = gctl_get_param(req, "size", &len);
239800f32ecbSAlexander Motin if (sizearg != NULL && len == sizeof(*sizearg) &&
239900f32ecbSAlexander Motin *sizearg > 0) {
240000f32ecbSAlexander Motin if (*sizearg > size) {
240100f32ecbSAlexander Motin gctl_error(req, "Size too big %lld > %lld.",
240200f32ecbSAlexander Motin (long long)*sizearg, (long long)size);
240300f32ecbSAlexander Motin return (-9);
240400f32ecbSAlexander Motin }
240500f32ecbSAlexander Motin size = *sizearg;
240600f32ecbSAlexander Motin }
240700f32ecbSAlexander Motin
240800f32ecbSAlexander Motin /* Handle strip argument. */
240900f32ecbSAlexander Motin strip = 131072;
241000f32ecbSAlexander Motin len = sizeof(*striparg);
241100f32ecbSAlexander Motin striparg = gctl_get_param(req, "strip", &len);
241200f32ecbSAlexander Motin if (striparg != NULL && len == sizeof(*striparg) &&
241300f32ecbSAlexander Motin *striparg > 0) {
241400f32ecbSAlexander Motin if (*striparg < sectorsize) {
241500f32ecbSAlexander Motin gctl_error(req, "Strip size too small.");
241600f32ecbSAlexander Motin return (-10);
241700f32ecbSAlexander Motin }
241800f32ecbSAlexander Motin if (*striparg % sectorsize != 0) {
241900f32ecbSAlexander Motin gctl_error(req, "Incorrect strip size.");
242000f32ecbSAlexander Motin return (-11);
242100f32ecbSAlexander Motin }
242200f32ecbSAlexander Motin strip = *striparg;
242300f32ecbSAlexander Motin }
242400f32ecbSAlexander Motin
242500f32ecbSAlexander Motin /* Round size down to strip or sector. */
242600f32ecbSAlexander Motin if (level == G_RAID_VOLUME_RL_RAID1 ||
242700f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_RAID3 ||
242800f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_SINGLE ||
242900f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_CONCAT)
243000f32ecbSAlexander Motin size -= (size % sectorsize);
243100f32ecbSAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID1E &&
243200f32ecbSAlexander Motin (numdisks & 1) != 0)
243300f32ecbSAlexander Motin size -= (size % (2 * strip));
243400f32ecbSAlexander Motin else
243500f32ecbSAlexander Motin size -= (size % strip);
243600f32ecbSAlexander Motin if (size <= 0) {
243700f32ecbSAlexander Motin gctl_error(req, "Size too small.");
243800f32ecbSAlexander Motin return (-13);
243900f32ecbSAlexander Motin }
244000f32ecbSAlexander Motin
244100f32ecbSAlexander Motin /* We have all we need, create things: volume, ... */
244200f32ecbSAlexander Motin pv = malloc(sizeof(*pv), M_MD_DDF, M_WAITOK | M_ZERO);
244300f32ecbSAlexander Motin ddf_vol_meta_create(&pv->pv_meta, &mdi->mdio_meta);
244400f32ecbSAlexander Motin pv->pv_started = 1;
244500f32ecbSAlexander Motin vol = g_raid_create_volume(sc, volname, -1);
244600f32ecbSAlexander Motin vol->v_md_data = pv;
244700f32ecbSAlexander Motin vol->v_raid_level = level;
244800f32ecbSAlexander Motin vol->v_raid_level_qualifier = qual;
244900f32ecbSAlexander Motin vol->v_strip_size = strip;
245000f32ecbSAlexander Motin vol->v_disks_count = numdisks;
245100f32ecbSAlexander Motin if (level == G_RAID_VOLUME_RL_RAID0 ||
245200f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_CONCAT ||
245300f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_SINGLE)
245400f32ecbSAlexander Motin vol->v_mediasize = size * numdisks;
245500f32ecbSAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID1)
245600f32ecbSAlexander Motin vol->v_mediasize = size;
245700f32ecbSAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID3 ||
245800f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_RAID4 ||
24598f12ca2eSAlexander Motin level == G_RAID_VOLUME_RL_RAID5)
246000f32ecbSAlexander Motin vol->v_mediasize = size * (numdisks - 1);
24618f12ca2eSAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID5R) {
24628f12ca2eSAlexander Motin vol->v_mediasize = size * (numdisks - 1);
24638f12ca2eSAlexander Motin vol->v_rotate_parity = 1024;
24648f12ca2eSAlexander Motin } else if (level == G_RAID_VOLUME_RL_RAID6 ||
246500f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_RAID5E ||
246600f32ecbSAlexander Motin level == G_RAID_VOLUME_RL_RAID5EE)
246700f32ecbSAlexander Motin vol->v_mediasize = size * (numdisks - 2);
24688f12ca2eSAlexander Motin else if (level == G_RAID_VOLUME_RL_RAIDMDF) {
24698f12ca2eSAlexander Motin if (numdisks < 5)
24708f12ca2eSAlexander Motin vol->v_mdf_pdisks = 2;
24718f12ca2eSAlexander Motin else
24728f12ca2eSAlexander Motin vol->v_mdf_pdisks = 3;
24738f12ca2eSAlexander Motin vol->v_mdf_polynomial = 0x11d;
24748f12ca2eSAlexander Motin vol->v_mdf_method = 0x00;
24758f12ca2eSAlexander Motin vol->v_mediasize = size * (numdisks - vol->v_mdf_pdisks);
24768f12ca2eSAlexander Motin } else { /* RAID1E */
247700f32ecbSAlexander Motin vol->v_mediasize = ((size * numdisks) / strip / 2) *
247800f32ecbSAlexander Motin strip;
247900f32ecbSAlexander Motin }
248000f32ecbSAlexander Motin vol->v_sectorsize = sectorsize;
248100f32ecbSAlexander Motin g_raid_start_volume(vol);
248200f32ecbSAlexander Motin
248300f32ecbSAlexander Motin /* , and subdisks. */
248400f32ecbSAlexander Motin for (i = 0; i < numdisks; i++) {
248500f32ecbSAlexander Motin disk = disks[i];
248600f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
248700f32ecbSAlexander Motin sd->sd_disk = disk;
248814f9f25bSAlexander Motin sd->sd_offset = offs[i];
248900f32ecbSAlexander Motin sd->sd_size = size;
249000f32ecbSAlexander Motin if (disk == NULL)
249100f32ecbSAlexander Motin continue;
249200f32ecbSAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
249300f32ecbSAlexander Motin g_raid_change_disk_state(disk,
249400f32ecbSAlexander Motin G_RAID_DISK_S_ACTIVE);
249500f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
249600f32ecbSAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
249700f32ecbSAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
249800f32ecbSAlexander Motin G_RAID_EVENT_SUBDISK);
249900f32ecbSAlexander Motin }
250000f32ecbSAlexander Motin
250100f32ecbSAlexander Motin /* Write metadata based on created entities. */
250200f32ecbSAlexander Motin G_RAID_DEBUG1(0, sc, "Array started.");
250300f32ecbSAlexander Motin g_raid_md_write_ddf(md, vol, NULL, NULL);
250400f32ecbSAlexander Motin
250500f32ecbSAlexander Motin /* Pickup any STALE/SPARE disks to refill array if needed. */
250600f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
250700f32ecbSAlexander Motin
250800f32ecbSAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_START,
250900f32ecbSAlexander Motin G_RAID_EVENT_VOLUME);
251000f32ecbSAlexander Motin return (0);
251100f32ecbSAlexander Motin }
251200f32ecbSAlexander Motin if (strcmp(verb, "add") == 0) {
251300f32ecbSAlexander Motin gctl_error(req, "`add` command is not applicable, "
251400f32ecbSAlexander Motin "use `label` instead.");
251500f32ecbSAlexander Motin return (-99);
251600f32ecbSAlexander Motin }
251700f32ecbSAlexander Motin if (strcmp(verb, "delete") == 0) {
25186871a543SAlexander Motin nodename = gctl_get_asciiparam(req, "arg0");
25196871a543SAlexander Motin if (nodename != NULL && strcasecmp(sc->sc_name, nodename) != 0)
25206871a543SAlexander Motin nodename = NULL;
25216871a543SAlexander Motin
252200f32ecbSAlexander Motin /* Full node destruction. */
25236871a543SAlexander Motin if (*nargs == 1 && nodename != NULL) {
252400f32ecbSAlexander Motin /* Check if some volume is still open. */
252500f32ecbSAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
252600f32ecbSAlexander Motin if (force != NULL && *force == 0 &&
252700f32ecbSAlexander Motin g_raid_nopens(sc) != 0) {
252800f32ecbSAlexander Motin gctl_error(req, "Some volume is still open.");
252900f32ecbSAlexander Motin return (-4);
253000f32ecbSAlexander Motin }
253100f32ecbSAlexander Motin
253200f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
253300f32ecbSAlexander Motin if (disk->d_consumer)
253400f32ecbSAlexander Motin ddf_meta_erase(disk->d_consumer);
253500f32ecbSAlexander Motin }
253600f32ecbSAlexander Motin g_raid_destroy_node(sc, 0);
253700f32ecbSAlexander Motin return (0);
253800f32ecbSAlexander Motin }
253900f32ecbSAlexander Motin
254000f32ecbSAlexander Motin /* Destroy specified volume. If it was last - all node. */
25416871a543SAlexander Motin if (*nargs > 2) {
254200f32ecbSAlexander Motin gctl_error(req, "Invalid number of arguments.");
254300f32ecbSAlexander Motin return (-1);
254400f32ecbSAlexander Motin }
25456871a543SAlexander Motin volname = gctl_get_asciiparam(req,
25466871a543SAlexander Motin nodename != NULL ? "arg1" : "arg0");
254700f32ecbSAlexander Motin if (volname == NULL) {
254800f32ecbSAlexander Motin gctl_error(req, "No volume name.");
254900f32ecbSAlexander Motin return (-2);
255000f32ecbSAlexander Motin }
255100f32ecbSAlexander Motin
255200f32ecbSAlexander Motin /* Search for volume. */
255300f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
255400f32ecbSAlexander Motin if (strcmp(vol->v_name, volname) == 0)
255500f32ecbSAlexander Motin break;
25566871a543SAlexander Motin pp = vol->v_provider;
25576871a543SAlexander Motin if (pp == NULL)
25586871a543SAlexander Motin continue;
25596871a543SAlexander Motin if (strcmp(pp->name, volname) == 0)
25606871a543SAlexander Motin break;
25616871a543SAlexander Motin if (strncmp(pp->name, "raid/", 5) == 0 &&
25626871a543SAlexander Motin strcmp(pp->name + 5, volname) == 0)
25636871a543SAlexander Motin break;
256400f32ecbSAlexander Motin }
256500f32ecbSAlexander Motin if (vol == NULL) {
256600f32ecbSAlexander Motin i = strtol(volname, &tmp, 10);
256700f32ecbSAlexander Motin if (verb != volname && tmp[0] == 0) {
256800f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
256900f32ecbSAlexander Motin if (vol->v_global_id == i)
257000f32ecbSAlexander Motin break;
257100f32ecbSAlexander Motin }
257200f32ecbSAlexander Motin }
257300f32ecbSAlexander Motin }
257400f32ecbSAlexander Motin if (vol == NULL) {
257500f32ecbSAlexander Motin gctl_error(req, "Volume '%s' not found.", volname);
257600f32ecbSAlexander Motin return (-3);
257700f32ecbSAlexander Motin }
257800f32ecbSAlexander Motin
257900f32ecbSAlexander Motin /* Check if volume is still open. */
258000f32ecbSAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
258100f32ecbSAlexander Motin if (force != NULL && *force == 0 &&
258200f32ecbSAlexander Motin vol->v_provider_open != 0) {
258300f32ecbSAlexander Motin gctl_error(req, "Volume is still open.");
258400f32ecbSAlexander Motin return (-4);
258500f32ecbSAlexander Motin }
258600f32ecbSAlexander Motin
258700f32ecbSAlexander Motin /* Destroy volume and potentially node. */
258800f32ecbSAlexander Motin i = 0;
258900f32ecbSAlexander Motin TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next)
259000f32ecbSAlexander Motin i++;
259100f32ecbSAlexander Motin if (i >= 2) {
259200f32ecbSAlexander Motin g_raid_destroy_volume(vol);
259300f32ecbSAlexander Motin g_raid_md_ddf_purge_disks(sc);
259400f32ecbSAlexander Motin g_raid_md_write_ddf(md, NULL, NULL, NULL);
259500f32ecbSAlexander Motin } else {
259600f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
259700f32ecbSAlexander Motin if (disk->d_consumer)
259800f32ecbSAlexander Motin ddf_meta_erase(disk->d_consumer);
259900f32ecbSAlexander Motin }
260000f32ecbSAlexander Motin g_raid_destroy_node(sc, 0);
260100f32ecbSAlexander Motin }
260200f32ecbSAlexander Motin return (0);
260300f32ecbSAlexander Motin }
260400f32ecbSAlexander Motin if (strcmp(verb, "remove") == 0 ||
260500f32ecbSAlexander Motin strcmp(verb, "fail") == 0) {
260600f32ecbSAlexander Motin if (*nargs < 2) {
260700f32ecbSAlexander Motin gctl_error(req, "Invalid number of arguments.");
260800f32ecbSAlexander Motin return (-1);
260900f32ecbSAlexander Motin }
261000f32ecbSAlexander Motin for (i = 1; i < *nargs; i++) {
261100f32ecbSAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i);
261200f32ecbSAlexander Motin diskname = gctl_get_asciiparam(req, arg);
261300f32ecbSAlexander Motin if (diskname == NULL) {
261400f32ecbSAlexander Motin gctl_error(req, "No disk name (%s).", arg);
261500f32ecbSAlexander Motin error = -2;
261600f32ecbSAlexander Motin break;
261700f32ecbSAlexander Motin }
26188510f61aSXin LI if (strncmp(diskname, _PATH_DEV, 5) == 0)
261900f32ecbSAlexander Motin diskname += 5;
262000f32ecbSAlexander Motin
262100f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
262200f32ecbSAlexander Motin if (disk->d_consumer != NULL &&
262300f32ecbSAlexander Motin disk->d_consumer->provider != NULL &&
262400f32ecbSAlexander Motin strcmp(disk->d_consumer->provider->name,
262500f32ecbSAlexander Motin diskname) == 0)
262600f32ecbSAlexander Motin break;
262700f32ecbSAlexander Motin }
262800f32ecbSAlexander Motin if (disk == NULL) {
262900f32ecbSAlexander Motin gctl_error(req, "Disk '%s' not found.",
263000f32ecbSAlexander Motin diskname);
263100f32ecbSAlexander Motin error = -3;
263200f32ecbSAlexander Motin break;
263300f32ecbSAlexander Motin }
263400f32ecbSAlexander Motin
263500f32ecbSAlexander Motin if (strcmp(verb, "fail") == 0) {
263600f32ecbSAlexander Motin g_raid_md_fail_disk_ddf(md, NULL, disk);
263700f32ecbSAlexander Motin continue;
263800f32ecbSAlexander Motin }
263900f32ecbSAlexander Motin
264000f32ecbSAlexander Motin /* Erase metadata on deleting disk and destroy it. */
264100f32ecbSAlexander Motin ddf_meta_erase(disk->d_consumer);
264200f32ecbSAlexander Motin g_raid_destroy_disk(disk);
264300f32ecbSAlexander Motin }
264400f32ecbSAlexander Motin g_raid_md_ddf_purge_volumes(sc);
264500f32ecbSAlexander Motin
264600f32ecbSAlexander Motin /* Write updated metadata to remaining disks. */
264700f32ecbSAlexander Motin g_raid_md_write_ddf(md, NULL, NULL, NULL);
264800f32ecbSAlexander Motin
264900f32ecbSAlexander Motin /* Check if anything left. */
265000f32ecbSAlexander Motin if (g_raid_ndisks(sc, -1) == 0)
265100f32ecbSAlexander Motin g_raid_destroy_node(sc, 0);
265200f32ecbSAlexander Motin else
265300f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
265400f32ecbSAlexander Motin return (error);
265500f32ecbSAlexander Motin }
265600f32ecbSAlexander Motin if (strcmp(verb, "insert") == 0) {
265700f32ecbSAlexander Motin if (*nargs < 2) {
265800f32ecbSAlexander Motin gctl_error(req, "Invalid number of arguments.");
265900f32ecbSAlexander Motin return (-1);
266000f32ecbSAlexander Motin }
266100f32ecbSAlexander Motin for (i = 1; i < *nargs; i++) {
266200f32ecbSAlexander Motin /* Get disk name. */
266300f32ecbSAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i);
266400f32ecbSAlexander Motin diskname = gctl_get_asciiparam(req, arg);
266500f32ecbSAlexander Motin if (diskname == NULL) {
266600f32ecbSAlexander Motin gctl_error(req, "No disk name (%s).", arg);
266700f32ecbSAlexander Motin error = -3;
266800f32ecbSAlexander Motin break;
266900f32ecbSAlexander Motin }
267000f32ecbSAlexander Motin
267100f32ecbSAlexander Motin /* Try to find provider with specified name. */
267200f32ecbSAlexander Motin g_topology_lock();
267300f32ecbSAlexander Motin cp = g_raid_open_consumer(sc, diskname);
267400f32ecbSAlexander Motin if (cp == NULL) {
267500f32ecbSAlexander Motin gctl_error(req, "Can't open disk '%s'.",
267600f32ecbSAlexander Motin diskname);
267700f32ecbSAlexander Motin g_topology_unlock();
267800f32ecbSAlexander Motin error = -4;
267900f32ecbSAlexander Motin break;
268000f32ecbSAlexander Motin }
268100f32ecbSAlexander Motin pp = cp->provider;
268200f32ecbSAlexander Motin g_topology_unlock();
268300f32ecbSAlexander Motin
268400f32ecbSAlexander Motin pd = malloc(sizeof(*pd), M_MD_DDF, M_WAITOK | M_ZERO);
268500f32ecbSAlexander Motin
268600f32ecbSAlexander Motin disk = g_raid_create_disk(sc);
268700f32ecbSAlexander Motin disk->d_consumer = cp;
268800f32ecbSAlexander Motin disk->d_md_data = (void *)pd;
268900f32ecbSAlexander Motin cp->private = disk;
269000f32ecbSAlexander Motin
2691609a7474SAlexander Motin g_raid_get_disk_info(disk);
269200f32ecbSAlexander Motin
269300f32ecbSAlexander Motin /* Welcome the "new" disk. */
269400f32ecbSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
269500f32ecbSAlexander Motin ddf_meta_create(disk, &mdi->mdio_meta);
2696d525d875SAlexander Motin sa = ddf_meta_find_sa(&pd->pd_meta, 1);
2697d525d875SAlexander Motin if (sa != NULL) {
2698d525d875SAlexander Motin SET32D(&pd->pd_meta, sa->Signature,
2699d525d875SAlexander Motin DDF_SA_SIGNATURE);
2700d525d875SAlexander Motin SET8D(&pd->pd_meta, sa->Spare_Type, 0);
2701d525d875SAlexander Motin SET16D(&pd->pd_meta, sa->Populated_SAEs, 0);
2702d525d875SAlexander Motin SET16D(&pd->pd_meta, sa->MAX_SAE_Supported,
2703d525d875SAlexander Motin (GET16(&pd->pd_meta, hdr->Configuration_Record_Length) *
2704d525d875SAlexander Motin pd->pd_meta.sectorsize -
2705d525d875SAlexander Motin sizeof(struct ddf_sa_record)) /
2706d525d875SAlexander Motin sizeof(struct ddf_sa_entry));
2707d525d875SAlexander Motin }
270800f32ecbSAlexander Motin if (mdi->mdio_meta.hdr == NULL)
270900f32ecbSAlexander Motin ddf_meta_copy(&mdi->mdio_meta, &pd->pd_meta);
271000f32ecbSAlexander Motin else
271100f32ecbSAlexander Motin ddf_meta_update(&mdi->mdio_meta, &pd->pd_meta);
2712d525d875SAlexander Motin g_raid_md_write_ddf(md, NULL, NULL, NULL);
271300f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
271400f32ecbSAlexander Motin }
271500f32ecbSAlexander Motin return (error);
271600f32ecbSAlexander Motin }
271700f32ecbSAlexander Motin return (-100);
271800f32ecbSAlexander Motin }
271900f32ecbSAlexander Motin
272000f32ecbSAlexander Motin static int
g_raid_md_write_ddf(struct g_raid_md_object * md,struct g_raid_volume * tvol,struct g_raid_subdisk * tsd,struct g_raid_disk * tdisk)272100f32ecbSAlexander Motin g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
272200f32ecbSAlexander Motin struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
272300f32ecbSAlexander Motin {
272400f32ecbSAlexander Motin struct g_raid_softc *sc;
272500f32ecbSAlexander Motin struct g_raid_volume *vol;
272600f32ecbSAlexander Motin struct g_raid_subdisk *sd;
272700f32ecbSAlexander Motin struct g_raid_disk *disk;
272800f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
272900f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
273000f32ecbSAlexander Motin struct g_raid_md_ddf_object *mdi;
273100f32ecbSAlexander Motin struct ddf_meta *gmeta;
273200f32ecbSAlexander Motin struct ddf_vol_meta *vmeta;
273300f32ecbSAlexander Motin struct ddf_vdc_record *vdc;
2734d525d875SAlexander Motin struct ddf_sa_record *sa;
273500f32ecbSAlexander Motin uint64_t *val2;
273600f32ecbSAlexander Motin int i, j, pos, bvd, size;
273700f32ecbSAlexander Motin
273800f32ecbSAlexander Motin sc = md->mdo_softc;
273900f32ecbSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
274000f32ecbSAlexander Motin gmeta = &mdi->mdio_meta;
274100f32ecbSAlexander Motin
274200f32ecbSAlexander Motin if (sc->sc_stopping == G_RAID_DESTROY_HARD)
274300f32ecbSAlexander Motin return (0);
274400f32ecbSAlexander Motin
274547e98096SAlexander Motin /*
274647e98096SAlexander Motin * Clear disk flags to let only really needed ones to be reset.
274747e98096SAlexander Motin * Do it only if there are no volumes in starting state now,
274847e98096SAlexander Motin * as they can update disk statuses yet and we may kill innocent.
274947e98096SAlexander Motin */
275047e98096SAlexander Motin if (mdi->mdio_starting == 0) {
275147e98096SAlexander Motin for (i = 0; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
275247e98096SAlexander Motin if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
275347e98096SAlexander Motin continue;
275447e98096SAlexander Motin SET16(gmeta, pdr->entry[i].PD_Type,
275547e98096SAlexander Motin GET16(gmeta, pdr->entry[i].PD_Type) &
2756d525d875SAlexander Motin ~(DDF_PDE_PARTICIPATING |
2757d525d875SAlexander Motin DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE));
275847e98096SAlexander Motin if ((GET16(gmeta, pdr->entry[i].PD_State) &
275947e98096SAlexander Motin DDF_PDE_PFA) == 0)
276047e98096SAlexander Motin SET16(gmeta, pdr->entry[i].PD_State, 0);
276147e98096SAlexander Motin }
276247e98096SAlexander Motin }
276347e98096SAlexander Motin
276447e98096SAlexander Motin /* Generate/update new per-volume metadata. */
276500f32ecbSAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
276600f32ecbSAlexander Motin pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
276747e98096SAlexander Motin if (vol->v_stopping || !pv->pv_started)
276847e98096SAlexander Motin continue;
276900f32ecbSAlexander Motin vmeta = &pv->pv_meta;
277000f32ecbSAlexander Motin
277100f32ecbSAlexander Motin SET32(vmeta, vdc->Sequence_Number,
277200f32ecbSAlexander Motin GET32(vmeta, vdc->Sequence_Number) + 1);
277300f32ecbSAlexander Motin if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
277400f32ecbSAlexander Motin vol->v_disks_count % 2 == 0)
277500f32ecbSAlexander Motin SET16(vmeta, vdc->Primary_Element_Count, 2);
277600f32ecbSAlexander Motin else
277700f32ecbSAlexander Motin SET16(vmeta, vdc->Primary_Element_Count,
277800f32ecbSAlexander Motin vol->v_disks_count);
277900f32ecbSAlexander Motin SET8(vmeta, vdc->Stripe_Size,
278000f32ecbSAlexander Motin ffs(vol->v_strip_size / vol->v_sectorsize) - 1);
278100f32ecbSAlexander Motin if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E &&
278200f32ecbSAlexander Motin vol->v_disks_count % 2 == 0) {
278300f32ecbSAlexander Motin SET8(vmeta, vdc->Primary_RAID_Level,
278400f32ecbSAlexander Motin DDF_VDCR_RAID1);
278500f32ecbSAlexander Motin SET8(vmeta, vdc->RLQ, 0);
278600f32ecbSAlexander Motin SET8(vmeta, vdc->Secondary_Element_Count,
278700f32ecbSAlexander Motin vol->v_disks_count / 2);
278800f32ecbSAlexander Motin SET8(vmeta, vdc->Secondary_RAID_Level, 0);
278900f32ecbSAlexander Motin } else {
279000f32ecbSAlexander Motin SET8(vmeta, vdc->Primary_RAID_Level,
279100f32ecbSAlexander Motin vol->v_raid_level);
279200f32ecbSAlexander Motin SET8(vmeta, vdc->RLQ,
279300f32ecbSAlexander Motin vol->v_raid_level_qualifier);
279400f32ecbSAlexander Motin SET8(vmeta, vdc->Secondary_Element_Count, 1);
279500f32ecbSAlexander Motin SET8(vmeta, vdc->Secondary_RAID_Level, 0);
279600f32ecbSAlexander Motin }
279700f32ecbSAlexander Motin SET8(vmeta, vdc->Secondary_Element_Seq, 0);
279800f32ecbSAlexander Motin SET64(vmeta, vdc->Block_Count, 0);
279900f32ecbSAlexander Motin SET64(vmeta, vdc->VD_Size, vol->v_mediasize / vol->v_sectorsize);
280000f32ecbSAlexander Motin SET16(vmeta, vdc->Block_Size, vol->v_sectorsize);
28018f12ca2eSAlexander Motin SET8(vmeta, vdc->Rotate_Parity_count,
28028f12ca2eSAlexander Motin fls(vol->v_rotate_parity) - 1);
28038f12ca2eSAlexander Motin SET8(vmeta, vdc->MDF_Parity_Disks, vol->v_mdf_pdisks);
28048f12ca2eSAlexander Motin SET16(vmeta, vdc->MDF_Parity_Generator_Polynomial,
28058f12ca2eSAlexander Motin vol->v_mdf_polynomial);
28068f12ca2eSAlexander Motin SET8(vmeta, vdc->MDF_Constant_Generation_Method,
28078f12ca2eSAlexander Motin vol->v_mdf_method);
280800f32ecbSAlexander Motin
280900f32ecbSAlexander Motin SET16(vmeta, vde->VD_Number, vol->v_global_id);
281000f32ecbSAlexander Motin if (vol->v_state <= G_RAID_VOLUME_S_BROKEN)
281100f32ecbSAlexander Motin SET8(vmeta, vde->VD_State, DDF_VDE_FAILED);
281200f32ecbSAlexander Motin else if (vol->v_state <= G_RAID_VOLUME_S_DEGRADED)
281300f32ecbSAlexander Motin SET8(vmeta, vde->VD_State, DDF_VDE_DEGRADED);
281400f32ecbSAlexander Motin else if (vol->v_state <= G_RAID_VOLUME_S_SUBOPTIMAL)
281500f32ecbSAlexander Motin SET8(vmeta, vde->VD_State, DDF_VDE_PARTIAL);
281600f32ecbSAlexander Motin else
281700f32ecbSAlexander Motin SET8(vmeta, vde->VD_State, DDF_VDE_OPTIMAL);
281847e98096SAlexander Motin if (vol->v_dirty ||
281947e98096SAlexander Motin g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_STALE) > 0 ||
282047e98096SAlexander Motin g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_RESYNC) > 0)
282100f32ecbSAlexander Motin SET8(vmeta, vde->VD_State,
282200f32ecbSAlexander Motin GET8(vmeta, vde->VD_State) | DDF_VDE_DIRTY);
282300f32ecbSAlexander Motin SET8(vmeta, vde->Init_State, DDF_VDE_INIT_FULL); // XXX
282400f32ecbSAlexander Motin ddf_meta_put_name(vmeta, vol->v_name);
282500f32ecbSAlexander Motin
282600f32ecbSAlexander Motin for (i = 0; i < vol->v_disks_count; i++) {
282700f32ecbSAlexander Motin sd = &vol->v_subdisks[i];
282800f32ecbSAlexander Motin bvd = i / GET16(vmeta, vdc->Primary_Element_Count);
282900f32ecbSAlexander Motin pos = i % GET16(vmeta, vdc->Primary_Element_Count);
283047e98096SAlexander Motin disk = sd->sd_disk;
283147e98096SAlexander Motin if (disk != NULL) {
283247e98096SAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
283300f32ecbSAlexander Motin if (vmeta->bvdc[bvd] == NULL) {
283400f32ecbSAlexander Motin size = GET16(vmeta,
283500f32ecbSAlexander Motin hdr->Configuration_Record_Length) *
283600f32ecbSAlexander Motin vmeta->sectorsize;
283747e98096SAlexander Motin vmeta->bvdc[bvd] = malloc(size,
283847e98096SAlexander Motin M_MD_DDF, M_WAITOK);
283947e98096SAlexander Motin memset(vmeta->bvdc[bvd], 0xff, size);
284000f32ecbSAlexander Motin }
284147e98096SAlexander Motin memcpy(vmeta->bvdc[bvd], vmeta->vdc,
284247e98096SAlexander Motin sizeof(struct ddf_vdc_record));
284347e98096SAlexander Motin SET8(vmeta, bvdc[bvd]->Secondary_Element_Seq, bvd);
284400f32ecbSAlexander Motin SET64(vmeta, bvdc[bvd]->Block_Count,
284500f32ecbSAlexander Motin sd->sd_size / vol->v_sectorsize);
284600f32ecbSAlexander Motin SET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos],
284700f32ecbSAlexander Motin GET32(&pd->pd_meta, pdd->PD_Reference));
284800f32ecbSAlexander Motin val2 = (uint64_t *)&(vmeta->bvdc[bvd]->Physical_Disk_Sequence[
284900f32ecbSAlexander Motin GET16(vmeta, hdr->Max_Primary_Element_Entries)]);
285000f32ecbSAlexander Motin SET64P(vmeta, val2 + pos,
285100f32ecbSAlexander Motin sd->sd_offset / vol->v_sectorsize);
285247e98096SAlexander Motin }
285347e98096SAlexander Motin if (vmeta->bvdc[bvd] == NULL)
285447e98096SAlexander Motin continue;
285500f32ecbSAlexander Motin
285600f32ecbSAlexander Motin j = ddf_meta_find_pd(gmeta, NULL,
285747e98096SAlexander Motin GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]));
285800f32ecbSAlexander Motin if (j < 0)
285900f32ecbSAlexander Motin continue;
28601229e83dSAlexander Motin SET16(gmeta, pdr->entry[j].PD_Type,
28611229e83dSAlexander Motin GET16(gmeta, pdr->entry[j].PD_Type) |
286200f32ecbSAlexander Motin DDF_PDE_PARTICIPATING);
286347e98096SAlexander Motin if (sd->sd_state == G_RAID_SUBDISK_S_NONE)
28641229e83dSAlexander Motin SET16(gmeta, pdr->entry[j].PD_State,
28651229e83dSAlexander Motin GET16(gmeta, pdr->entry[j].PD_State) |
2866d525d875SAlexander Motin (DDF_PDE_FAILED | DDF_PDE_MISSING));
286747e98096SAlexander Motin else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED)
28681229e83dSAlexander Motin SET16(gmeta, pdr->entry[j].PD_State,
28691229e83dSAlexander Motin GET16(gmeta, pdr->entry[j].PD_State) |
2870d525d875SAlexander Motin (DDF_PDE_FAILED | DDF_PDE_PFA));
287147e98096SAlexander Motin else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD)
28721229e83dSAlexander Motin SET16(gmeta, pdr->entry[j].PD_State,
28731229e83dSAlexander Motin GET16(gmeta, pdr->entry[j].PD_State) |
2874d525d875SAlexander Motin DDF_PDE_REBUILD);
287500f32ecbSAlexander Motin else
28761229e83dSAlexander Motin SET16(gmeta, pdr->entry[j].PD_State,
28771229e83dSAlexander Motin GET16(gmeta, pdr->entry[j].PD_State) |
287800f32ecbSAlexander Motin DDF_PDE_ONLINE);
287900f32ecbSAlexander Motin }
288000f32ecbSAlexander Motin }
288100f32ecbSAlexander Motin
2882d525d875SAlexander Motin /* Mark spare and failed disks as such. */
2883d525d875SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
2884d525d875SAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2885d525d875SAlexander Motin i = ddf_meta_find_pd(gmeta, NULL,
2886d525d875SAlexander Motin GET32(&pd->pd_meta, pdd->PD_Reference));
2887d525d875SAlexander Motin if (i < 0)
2888d525d875SAlexander Motin continue;
2889d525d875SAlexander Motin if (disk->d_state == G_RAID_DISK_S_FAILED) {
28901229e83dSAlexander Motin SET16(gmeta, pdr->entry[i].PD_State,
28911229e83dSAlexander Motin GET16(gmeta, pdr->entry[i].PD_State) |
2892d525d875SAlexander Motin (DDF_PDE_FAILED | DDF_PDE_PFA));
2893d525d875SAlexander Motin }
2894d525d875SAlexander Motin if (disk->d_state != G_RAID_DISK_S_SPARE)
2895d525d875SAlexander Motin continue;
2896d525d875SAlexander Motin sa = ddf_meta_find_sa(&pd->pd_meta, 0);
2897d525d875SAlexander Motin if (sa == NULL ||
2898d525d875SAlexander Motin (GET8D(&pd->pd_meta, sa->Spare_Type) &
2899d525d875SAlexander Motin DDF_SAR_TYPE_DEDICATED) == 0) {
2900d525d875SAlexander Motin SET16(gmeta, pdr->entry[i].PD_Type,
2901d525d875SAlexander Motin GET16(gmeta, pdr->entry[i].PD_Type) |
2902d525d875SAlexander Motin DDF_PDE_GLOBAL_SPARE);
2903d525d875SAlexander Motin } else {
2904d525d875SAlexander Motin SET16(gmeta, pdr->entry[i].PD_Type,
2905d525d875SAlexander Motin GET16(gmeta, pdr->entry[i].PD_Type) |
2906d525d875SAlexander Motin DDF_PDE_CONFIG_SPARE);
2907d525d875SAlexander Motin }
29081229e83dSAlexander Motin SET16(gmeta, pdr->entry[i].PD_State,
29091229e83dSAlexander Motin GET16(gmeta, pdr->entry[i].PD_State) |
2910d525d875SAlexander Motin DDF_PDE_ONLINE);
2911d525d875SAlexander Motin }
2912d525d875SAlexander Motin
291347e98096SAlexander Motin /* Remove disks without "participating" flag (unused). */
291447e98096SAlexander Motin for (i = 0, j = -1; i < GET16(gmeta, pdr->Populated_PDEs); i++) {
291547e98096SAlexander Motin if (isff(gmeta->pdr->entry[i].PD_GUID, 24))
291647e98096SAlexander Motin continue;
2917d525d875SAlexander Motin if ((GET16(gmeta, pdr->entry[i].PD_Type) &
2918d525d875SAlexander Motin (DDF_PDE_PARTICIPATING |
2919d525d875SAlexander Motin DDF_PDE_GLOBAL_SPARE | DDF_PDE_CONFIG_SPARE)) != 0 ||
2920d525d875SAlexander Motin g_raid_md_ddf_get_disk(sc,
2921d525d875SAlexander Motin NULL, GET32(gmeta, pdr->entry[i].PD_Reference)) != NULL)
292247e98096SAlexander Motin j = i;
292347e98096SAlexander Motin else
292447e98096SAlexander Motin memset(&gmeta->pdr->entry[i], 0xff,
292547e98096SAlexander Motin sizeof(struct ddf_pd_entry));
292647e98096SAlexander Motin }
292747e98096SAlexander Motin SET16(gmeta, pdr->Populated_PDEs, j + 1);
292847e98096SAlexander Motin
292947e98096SAlexander Motin /* Update per-disk metadata and write them. */
293000f32ecbSAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
293100f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
2932d525d875SAlexander Motin if (disk->d_state != G_RAID_DISK_S_ACTIVE &&
2933d525d875SAlexander Motin disk->d_state != G_RAID_DISK_S_SPARE)
293400f32ecbSAlexander Motin continue;
293547e98096SAlexander Motin /* Update PDR. */
293600f32ecbSAlexander Motin memcpy(pd->pd_meta.pdr, gmeta->pdr,
293700f32ecbSAlexander Motin GET32(&pd->pd_meta, hdr->pdr_length) *
293800f32ecbSAlexander Motin pd->pd_meta.sectorsize);
293947e98096SAlexander Motin /* Update VDR. */
294047e98096SAlexander Motin SET16(&pd->pd_meta, vdr->Populated_VDEs, 0);
294147e98096SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
294247e98096SAlexander Motin if (vol->v_stopping)
294347e98096SAlexander Motin continue;
294400f32ecbSAlexander Motin pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
294500f32ecbSAlexander Motin i = ddf_meta_find_vd(&pd->pd_meta,
294600f32ecbSAlexander Motin pv->pv_meta.vde->VD_GUID);
294700f32ecbSAlexander Motin if (i < 0)
294800f32ecbSAlexander Motin i = ddf_meta_find_vd(&pd->pd_meta, NULL);
294900f32ecbSAlexander Motin if (i >= 0)
295000f32ecbSAlexander Motin memcpy(&pd->pd_meta.vdr->entry[i],
295100f32ecbSAlexander Motin pv->pv_meta.vde,
295200f32ecbSAlexander Motin sizeof(struct ddf_vd_entry));
295347e98096SAlexander Motin }
295447e98096SAlexander Motin /* Update VDC. */
29552b9c925fSAlexander Motin if (mdi->mdio_starting == 0) {
29562b9c925fSAlexander Motin /* Remove all VDCs to restore needed later. */
29572b9c925fSAlexander Motin j = GETCRNUM(&pd->pd_meta);
29582b9c925fSAlexander Motin for (i = 0; i < j; i++) {
29592b9c925fSAlexander Motin vdc = GETVDCPTR(&pd->pd_meta, i);
29602b9c925fSAlexander Motin if (GET32D(&pd->pd_meta, vdc->Signature) !=
29612b9c925fSAlexander Motin DDF_VDCR_SIGNATURE)
29622b9c925fSAlexander Motin continue;
29632b9c925fSAlexander Motin SET32D(&pd->pd_meta, vdc->Signature, 0xffffffff);
29642b9c925fSAlexander Motin }
29652b9c925fSAlexander Motin }
296647e98096SAlexander Motin TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
296747e98096SAlexander Motin vol = sd->sd_volume;
296847e98096SAlexander Motin if (vol->v_stopping)
296947e98096SAlexander Motin continue;
297047e98096SAlexander Motin pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
297147e98096SAlexander Motin vmeta = &pv->pv_meta;
297200f32ecbSAlexander Motin vdc = ddf_meta_find_vdc(&pd->pd_meta,
297347e98096SAlexander Motin vmeta->vde->VD_GUID);
297400f32ecbSAlexander Motin if (vdc == NULL)
297500f32ecbSAlexander Motin vdc = ddf_meta_find_vdc(&pd->pd_meta, NULL);
297600f32ecbSAlexander Motin if (vdc != NULL) {
297700f32ecbSAlexander Motin bvd = sd->sd_pos / GET16(vmeta,
297800f32ecbSAlexander Motin vdc->Primary_Element_Count);
297947e98096SAlexander Motin memcpy(vdc, vmeta->bvdc[bvd],
298000f32ecbSAlexander Motin GET16(&pd->pd_meta,
298100f32ecbSAlexander Motin hdr->Configuration_Record_Length) *
298200f32ecbSAlexander Motin pd->pd_meta.sectorsize);
298300f32ecbSAlexander Motin }
298400f32ecbSAlexander Motin }
298500f32ecbSAlexander Motin G_RAID_DEBUG(1, "Writing DDF metadata to %s",
298600f32ecbSAlexander Motin g_raid_get_diskname(disk));
298700f32ecbSAlexander Motin g_raid_md_ddf_print(&pd->pd_meta);
298800f32ecbSAlexander Motin ddf_meta_write(disk->d_consumer, &pd->pd_meta);
298900f32ecbSAlexander Motin }
299000f32ecbSAlexander Motin return (0);
299100f32ecbSAlexander Motin }
299200f32ecbSAlexander Motin
299300f32ecbSAlexander Motin static int
g_raid_md_fail_disk_ddf(struct g_raid_md_object * md,struct g_raid_subdisk * tsd,struct g_raid_disk * tdisk)299400f32ecbSAlexander Motin g_raid_md_fail_disk_ddf(struct g_raid_md_object *md,
299500f32ecbSAlexander Motin struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
299600f32ecbSAlexander Motin {
299700f32ecbSAlexander Motin struct g_raid_softc *sc;
299800f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
299900f32ecbSAlexander Motin struct g_raid_subdisk *sd;
300000f32ecbSAlexander Motin int i;
300100f32ecbSAlexander Motin
300200f32ecbSAlexander Motin sc = md->mdo_softc;
300300f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)tdisk->d_md_data;
300400f32ecbSAlexander Motin
300500f32ecbSAlexander Motin /* We can't fail disk that is not a part of array now. */
300600f32ecbSAlexander Motin if (tdisk->d_state != G_RAID_DISK_S_ACTIVE)
300700f32ecbSAlexander Motin return (-1);
300800f32ecbSAlexander Motin
300900f32ecbSAlexander Motin /*
301000f32ecbSAlexander Motin * Mark disk as failed in metadata and try to write that metadata
301100f32ecbSAlexander Motin * to the disk itself to prevent it's later resurrection as STALE.
301200f32ecbSAlexander Motin */
301300f32ecbSAlexander Motin G_RAID_DEBUG(1, "Writing DDF metadata to %s",
301400f32ecbSAlexander Motin g_raid_get_diskname(tdisk));
301500f32ecbSAlexander Motin i = ddf_meta_find_pd(&pd->pd_meta, NULL, GET32(&pd->pd_meta, pdd->PD_Reference));
301600f32ecbSAlexander Motin SET16(&pd->pd_meta, pdr->entry[i].PD_State, DDF_PDE_FAILED | DDF_PDE_PFA);
301700f32ecbSAlexander Motin if (tdisk->d_consumer != NULL)
301800f32ecbSAlexander Motin ddf_meta_write(tdisk->d_consumer, &pd->pd_meta);
301900f32ecbSAlexander Motin
302000f32ecbSAlexander Motin /* Change states. */
302100f32ecbSAlexander Motin g_raid_change_disk_state(tdisk, G_RAID_DISK_S_FAILED);
302200f32ecbSAlexander Motin TAILQ_FOREACH(sd, &tdisk->d_subdisks, sd_next) {
302300f32ecbSAlexander Motin g_raid_change_subdisk_state(sd,
302400f32ecbSAlexander Motin G_RAID_SUBDISK_S_FAILED);
302500f32ecbSAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_FAILED,
302600f32ecbSAlexander Motin G_RAID_EVENT_SUBDISK);
302700f32ecbSAlexander Motin }
302800f32ecbSAlexander Motin
302900f32ecbSAlexander Motin /* Write updated metadata to remaining disks. */
303000f32ecbSAlexander Motin g_raid_md_write_ddf(md, NULL, NULL, tdisk);
303100f32ecbSAlexander Motin
303200f32ecbSAlexander Motin g_raid_md_ddf_refill(sc);
303300f32ecbSAlexander Motin return (0);
303400f32ecbSAlexander Motin }
303500f32ecbSAlexander Motin
303600f32ecbSAlexander Motin static int
g_raid_md_free_disk_ddf(struct g_raid_md_object * md,struct g_raid_disk * disk)303700f32ecbSAlexander Motin g_raid_md_free_disk_ddf(struct g_raid_md_object *md,
303800f32ecbSAlexander Motin struct g_raid_disk *disk)
303900f32ecbSAlexander Motin {
304000f32ecbSAlexander Motin struct g_raid_md_ddf_perdisk *pd;
304100f32ecbSAlexander Motin
304200f32ecbSAlexander Motin pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
304300f32ecbSAlexander Motin ddf_meta_free(&pd->pd_meta);
304400f32ecbSAlexander Motin free(pd, M_MD_DDF);
304500f32ecbSAlexander Motin disk->d_md_data = NULL;
304600f32ecbSAlexander Motin return (0);
304700f32ecbSAlexander Motin }
304800f32ecbSAlexander Motin
304900f32ecbSAlexander Motin static int
g_raid_md_free_volume_ddf(struct g_raid_md_object * md,struct g_raid_volume * vol)305000f32ecbSAlexander Motin g_raid_md_free_volume_ddf(struct g_raid_md_object *md,
305100f32ecbSAlexander Motin struct g_raid_volume *vol)
305200f32ecbSAlexander Motin {
30532b9c925fSAlexander Motin struct g_raid_md_ddf_object *mdi;
305400f32ecbSAlexander Motin struct g_raid_md_ddf_pervolume *pv;
305500f32ecbSAlexander Motin
30562b9c925fSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
305700f32ecbSAlexander Motin pv = (struct g_raid_md_ddf_pervolume *)vol->v_md_data;
305800f32ecbSAlexander Motin ddf_vol_meta_free(&pv->pv_meta);
305900f32ecbSAlexander Motin if (!pv->pv_started) {
306000f32ecbSAlexander Motin pv->pv_started = 1;
30612b9c925fSAlexander Motin mdi->mdio_starting--;
306200f32ecbSAlexander Motin callout_stop(&pv->pv_start_co);
306300f32ecbSAlexander Motin }
3064eb3b1cd0SAlexander Motin free(pv, M_MD_DDF);
3065eb3b1cd0SAlexander Motin vol->v_md_data = NULL;
306600f32ecbSAlexander Motin return (0);
306700f32ecbSAlexander Motin }
306800f32ecbSAlexander Motin
306900f32ecbSAlexander Motin static int
g_raid_md_free_ddf(struct g_raid_md_object * md)307000f32ecbSAlexander Motin g_raid_md_free_ddf(struct g_raid_md_object *md)
307100f32ecbSAlexander Motin {
307200f32ecbSAlexander Motin struct g_raid_md_ddf_object *mdi;
307300f32ecbSAlexander Motin
307400f32ecbSAlexander Motin mdi = (struct g_raid_md_ddf_object *)md;
307500f32ecbSAlexander Motin if (!mdi->mdio_started) {
307600f32ecbSAlexander Motin mdi->mdio_started = 0;
307700f32ecbSAlexander Motin callout_stop(&mdi->mdio_start_co);
307800f32ecbSAlexander Motin G_RAID_DEBUG1(1, md->mdo_softc,
307900f32ecbSAlexander Motin "root_mount_rel %p", mdi->mdio_rootmount);
308000f32ecbSAlexander Motin root_mount_rel(mdi->mdio_rootmount);
308100f32ecbSAlexander Motin mdi->mdio_rootmount = NULL;
308200f32ecbSAlexander Motin }
308300f32ecbSAlexander Motin ddf_meta_free(&mdi->mdio_meta);
308400f32ecbSAlexander Motin return (0);
308500f32ecbSAlexander Motin }
308600f32ecbSAlexander Motin
3087c89d2fbeSAlexander Motin G_RAID_MD_DECLARE(ddf, "DDF");
3088