189b17223SAlexander Motin /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
489b17223SAlexander Motin * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
5e26083caSAlexander Motin * Copyright (c) 2000 - 2008 Søren Schmidt <sos@FreeBSD.org>
689b17223SAlexander Motin * All rights reserved.
789b17223SAlexander Motin *
889b17223SAlexander Motin * Redistribution and use in source and binary forms, with or without
989b17223SAlexander Motin * modification, are permitted provided that the following conditions
1089b17223SAlexander Motin * are met:
1189b17223SAlexander Motin * 1. Redistributions of source code must retain the above copyright
1289b17223SAlexander Motin * notice, this list of conditions and the following disclaimer.
1389b17223SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright
1489b17223SAlexander Motin * notice, this list of conditions and the following disclaimer in the
1589b17223SAlexander Motin * documentation and/or other materials provided with the distribution.
1689b17223SAlexander Motin *
1789b17223SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1889b17223SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1989b17223SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2089b17223SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2189b17223SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2289b17223SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2389b17223SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2489b17223SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2589b17223SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2689b17223SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2789b17223SAlexander Motin * SUCH DAMAGE.
2889b17223SAlexander Motin */
2989b17223SAlexander Motin
3089b17223SAlexander Motin #include <sys/param.h>
3189b17223SAlexander Motin #include <sys/bio.h>
3289b17223SAlexander Motin #include <sys/endian.h>
3389b17223SAlexander Motin #include <sys/kernel.h>
3489b17223SAlexander Motin #include <sys/kobj.h>
3589b17223SAlexander Motin #include <sys/limits.h>
3689b17223SAlexander Motin #include <sys/lock.h>
3789b17223SAlexander Motin #include <sys/malloc.h>
3889b17223SAlexander Motin #include <sys/mutex.h>
3989b17223SAlexander Motin #include <sys/systm.h>
4089b17223SAlexander Motin #include <sys/taskqueue.h>
412c385d51SSean Bruno #include <sys/disk.h>
4289b17223SAlexander Motin #include <geom/geom.h>
43ac03832eSConrad Meyer #include <geom/geom_dbg.h>
4489b17223SAlexander Motin #include "geom/raid/g_raid.h"
4589b17223SAlexander Motin #include "g_raid_md_if.h"
4689b17223SAlexander Motin
4789b17223SAlexander Motin static MALLOC_DEFINE(M_MD_INTEL, "md_intel_data", "GEOM_RAID Intel metadata");
4889b17223SAlexander Motin
4989b17223SAlexander Motin struct intel_raid_map {
5089b17223SAlexander Motin uint32_t offset;
5189b17223SAlexander Motin uint32_t disk_sectors;
5289b17223SAlexander Motin uint32_t stripe_count;
5389b17223SAlexander Motin uint16_t strip_sectors;
5489b17223SAlexander Motin uint8_t status;
5589b17223SAlexander Motin #define INTEL_S_READY 0x00
5689b17223SAlexander Motin #define INTEL_S_UNINITIALIZED 0x01
5789b17223SAlexander Motin #define INTEL_S_DEGRADED 0x02
5889b17223SAlexander Motin #define INTEL_S_FAILURE 0x03
5989b17223SAlexander Motin
6089b17223SAlexander Motin uint8_t type;
6189b17223SAlexander Motin #define INTEL_T_RAID0 0x00
6289b17223SAlexander Motin #define INTEL_T_RAID1 0x01
6389b17223SAlexander Motin #define INTEL_T_RAID5 0x05
6489b17223SAlexander Motin
6589b17223SAlexander Motin uint8_t total_disks;
6689b17223SAlexander Motin uint8_t total_domains;
6789b17223SAlexander Motin uint8_t failed_disk_num;
6889b17223SAlexander Motin uint8_t ddf;
69c1ad3fcfSJim Harris uint32_t offset_hi;
70c1ad3fcfSJim Harris uint32_t disk_sectors_hi;
71c1ad3fcfSJim Harris uint32_t stripe_count_hi;
72c1ad3fcfSJim Harris uint32_t filler_2[4];
7389b17223SAlexander Motin uint32_t disk_idx[1]; /* total_disks entries. */
7489b17223SAlexander Motin #define INTEL_DI_IDX 0x00ffffff
7589b17223SAlexander Motin #define INTEL_DI_RBLD 0x01000000
7689b17223SAlexander Motin } __packed;
7789b17223SAlexander Motin
7889b17223SAlexander Motin struct intel_raid_vol {
7989b17223SAlexander Motin uint8_t name[16];
800ff783dcSJohn Baldwin uint64_t total_sectors __packed;
8189b17223SAlexander Motin uint32_t state;
8289b17223SAlexander Motin #define INTEL_ST_BOOTABLE 0x00000001
8389b17223SAlexander Motin #define INTEL_ST_BOOT_DEVICE 0x00000002
8489b17223SAlexander Motin #define INTEL_ST_READ_COALESCING 0x00000004
8589b17223SAlexander Motin #define INTEL_ST_WRITE_COALESCING 0x00000008
8689b17223SAlexander Motin #define INTEL_ST_LAST_SHUTDOWN_DIRTY 0x00000010
8789b17223SAlexander Motin #define INTEL_ST_HIDDEN_AT_BOOT 0x00000020
8889b17223SAlexander Motin #define INTEL_ST_CURRENTLY_HIDDEN 0x00000040
8989b17223SAlexander Motin #define INTEL_ST_VERIFY_AND_FIX 0x00000080
9089b17223SAlexander Motin #define INTEL_ST_MAP_STATE_UNINIT 0x00000100
9189b17223SAlexander Motin #define INTEL_ST_NO_AUTO_RECOVERY 0x00000200
9289b17223SAlexander Motin #define INTEL_ST_CLONE_N_GO 0x00000400
9389b17223SAlexander Motin #define INTEL_ST_CLONE_MAN_SYNC 0x00000800
9489b17223SAlexander Motin #define INTEL_ST_CNG_MASTER_DISK_NUM 0x00001000
9589b17223SAlexander Motin uint32_t reserved;
9689b17223SAlexander Motin uint8_t migr_priority;
9789b17223SAlexander Motin uint8_t num_sub_vols;
9889b17223SAlexander Motin uint8_t tid;
9989b17223SAlexander Motin uint8_t cng_master_disk;
10089b17223SAlexander Motin uint16_t cache_policy;
10189b17223SAlexander Motin uint8_t cng_state;
102eb84fc95SAlexander Motin #define INTEL_CNGST_UPDATED 0
103eb84fc95SAlexander Motin #define INTEL_CNGST_NEEDS_UPDATE 1
104eb84fc95SAlexander Motin #define INTEL_CNGST_MASTER_MISSING 2
10589b17223SAlexander Motin uint8_t cng_sub_state;
10689b17223SAlexander Motin uint32_t filler_0[10];
10789b17223SAlexander Motin
10889b17223SAlexander Motin uint32_t curr_migr_unit;
10989b17223SAlexander Motin uint32_t checkpoint_id;
11089b17223SAlexander Motin uint8_t migr_state;
11189b17223SAlexander Motin uint8_t migr_type;
11289b17223SAlexander Motin #define INTEL_MT_INIT 0
11389b17223SAlexander Motin #define INTEL_MT_REBUILD 1
11489b17223SAlexander Motin #define INTEL_MT_VERIFY 2
11589b17223SAlexander Motin #define INTEL_MT_GEN_MIGR 3
11689b17223SAlexander Motin #define INTEL_MT_STATE_CHANGE 4
11789b17223SAlexander Motin #define INTEL_MT_REPAIR 5
11889b17223SAlexander Motin uint8_t dirty;
11989b17223SAlexander Motin uint8_t fs_state;
12089b17223SAlexander Motin uint16_t verify_errors;
12189b17223SAlexander Motin uint16_t bad_blocks;
122c1ad3fcfSJim Harris uint32_t curr_migr_unit_hi;
123c1ad3fcfSJim Harris uint32_t filler_1[3];
12489b17223SAlexander Motin struct intel_raid_map map[1]; /* 2 entries if migr_state != 0. */
12589b17223SAlexander Motin } __packed;
12689b17223SAlexander Motin
12789b17223SAlexander Motin struct intel_raid_disk {
12889b17223SAlexander Motin #define INTEL_SERIAL_LEN 16
12989b17223SAlexander Motin uint8_t serial[INTEL_SERIAL_LEN];
13089b17223SAlexander Motin uint32_t sectors;
13189b17223SAlexander Motin uint32_t id;
13289b17223SAlexander Motin uint32_t flags;
13389b17223SAlexander Motin #define INTEL_F_SPARE 0x01
13489b17223SAlexander Motin #define INTEL_F_ASSIGNED 0x02
13589b17223SAlexander Motin #define INTEL_F_FAILED 0x04
13689b17223SAlexander Motin #define INTEL_F_ONLINE 0x08
13726c538bcSAlexander Motin #define INTEL_F_DISABLED 0x80
138c1ad3fcfSJim Harris uint32_t owner_cfg_num;
139c1ad3fcfSJim Harris uint32_t sectors_hi;
140c1ad3fcfSJim Harris uint32_t filler[3];
14189b17223SAlexander Motin } __packed;
14289b17223SAlexander Motin
14389b17223SAlexander Motin struct intel_raid_conf {
14489b17223SAlexander Motin uint8_t intel_id[24];
14589b17223SAlexander Motin #define INTEL_MAGIC "Intel Raid ISM Cfg Sig. "
14689b17223SAlexander Motin
14789b17223SAlexander Motin uint8_t version[6];
14889b17223SAlexander Motin #define INTEL_VERSION_1000 "1.0.00" /* RAID0 */
14989b17223SAlexander Motin #define INTEL_VERSION_1100 "1.1.00" /* RAID1 */
15089b17223SAlexander Motin #define INTEL_VERSION_1200 "1.2.00" /* Many volumes */
15189b17223SAlexander Motin #define INTEL_VERSION_1201 "1.2.01" /* 3 or 4 disks */
15289b17223SAlexander Motin #define INTEL_VERSION_1202 "1.2.02" /* RAID5 */
15389b17223SAlexander Motin #define INTEL_VERSION_1204 "1.2.04" /* 5 or 6 disks */
15489b17223SAlexander Motin #define INTEL_VERSION_1206 "1.2.06" /* CNG */
15589b17223SAlexander Motin #define INTEL_VERSION_1300 "1.3.00" /* Attributes */
15689b17223SAlexander Motin
15789b17223SAlexander Motin uint8_t dummy_0[2];
15889b17223SAlexander Motin uint32_t checksum;
15989b17223SAlexander Motin uint32_t config_size;
16089b17223SAlexander Motin uint32_t config_id;
16189b17223SAlexander Motin uint32_t generation;
16289b17223SAlexander Motin uint32_t error_log_size;
16389b17223SAlexander Motin uint32_t attributes;
16489b17223SAlexander Motin #define INTEL_ATTR_RAID0 0x00000001
16589b17223SAlexander Motin #define INTEL_ATTR_RAID1 0x00000002
16689b17223SAlexander Motin #define INTEL_ATTR_RAID10 0x00000004
16789b17223SAlexander Motin #define INTEL_ATTR_RAID1E 0x00000008
16889b17223SAlexander Motin #define INTEL_ATTR_RAID5 0x00000010
16989b17223SAlexander Motin #define INTEL_ATTR_RAIDCNG 0x00000020
170f9462b9bSAlexander Motin #define INTEL_ATTR_EXT_STRIP 0x00000040
171f9462b9bSAlexander Motin #define INTEL_ATTR_NVM_CACHE 0x02000000
172f9462b9bSAlexander Motin #define INTEL_ATTR_2TB_DISK 0x04000000
173f9462b9bSAlexander Motin #define INTEL_ATTR_BBM 0x08000000
174f9462b9bSAlexander Motin #define INTEL_ATTR_NVM_CACHE2 0x10000000
17589b17223SAlexander Motin #define INTEL_ATTR_2TB 0x20000000
17689b17223SAlexander Motin #define INTEL_ATTR_PM 0x40000000
17789b17223SAlexander Motin #define INTEL_ATTR_CHECKSUM 0x80000000
17889b17223SAlexander Motin
17989b17223SAlexander Motin uint8_t total_disks;
18089b17223SAlexander Motin uint8_t total_volumes;
1814c95a241SAlexander Motin uint8_t error_log_pos;
1824c95a241SAlexander Motin uint8_t dummy_2[1];
1834c95a241SAlexander Motin uint32_t cache_size;
184511c69d9SAlexander Motin uint32_t orig_config_id;
1854c95a241SAlexander Motin uint32_t pwr_cycle_count;
1864c95a241SAlexander Motin uint32_t bbm_log_size;
1874c95a241SAlexander Motin uint32_t filler_0[35];
18889b17223SAlexander Motin struct intel_raid_disk disk[1]; /* total_disks entries. */
18989b17223SAlexander Motin /* Here goes total_volumes of struct intel_raid_vol. */
19089b17223SAlexander Motin } __packed;
19189b17223SAlexander Motin
192f9462b9bSAlexander Motin #define INTEL_ATTR_SUPPORTED ( INTEL_ATTR_RAID0 | INTEL_ATTR_RAID1 | \
193f9462b9bSAlexander Motin INTEL_ATTR_RAID10 | INTEL_ATTR_RAID1E | INTEL_ATTR_RAID5 | \
194f9462b9bSAlexander Motin INTEL_ATTR_RAIDCNG | INTEL_ATTR_EXT_STRIP | INTEL_ATTR_2TB_DISK | \
195f9462b9bSAlexander Motin INTEL_ATTR_2TB | INTEL_ATTR_PM | INTEL_ATTR_CHECKSUM )
196f9462b9bSAlexander Motin
19789b17223SAlexander Motin #define INTEL_MAX_MD_SIZE(ndisks) \
19889b17223SAlexander Motin (sizeof(struct intel_raid_conf) + \
19989b17223SAlexander Motin sizeof(struct intel_raid_disk) * (ndisks - 1) + \
20089b17223SAlexander Motin sizeof(struct intel_raid_vol) * 2 + \
20189b17223SAlexander Motin sizeof(struct intel_raid_map) * 2 + \
20289b17223SAlexander Motin sizeof(uint32_t) * (ndisks - 1) * 4)
20389b17223SAlexander Motin
20489b17223SAlexander Motin struct g_raid_md_intel_perdisk {
20589b17223SAlexander Motin struct intel_raid_conf *pd_meta;
20689b17223SAlexander Motin int pd_disk_pos;
20789b17223SAlexander Motin struct intel_raid_disk pd_disk_meta;
20889b17223SAlexander Motin };
20989b17223SAlexander Motin
21026c538bcSAlexander Motin struct g_raid_md_intel_pervolume {
21126c538bcSAlexander Motin int pv_volume_pos;
21226c538bcSAlexander Motin int pv_cng;
21326c538bcSAlexander Motin int pv_cng_man_sync;
21426c538bcSAlexander Motin int pv_cng_master_disk;
21526c538bcSAlexander Motin };
21626c538bcSAlexander Motin
21789b17223SAlexander Motin struct g_raid_md_intel_object {
21889b17223SAlexander Motin struct g_raid_md_object mdio_base;
21989b17223SAlexander Motin uint32_t mdio_config_id;
2204c10c25eSAlexander Motin uint32_t mdio_orig_config_id;
22189b17223SAlexander Motin uint32_t mdio_generation;
22289b17223SAlexander Motin struct intel_raid_conf *mdio_meta;
22389b17223SAlexander Motin struct callout mdio_start_co; /* STARTING state timer. */
22489b17223SAlexander Motin int mdio_disks_present;
22589b17223SAlexander Motin int mdio_started;
22689b17223SAlexander Motin int mdio_incomplete;
22789b17223SAlexander Motin struct root_hold_token *mdio_rootmount; /* Root mount delay token. */
22889b17223SAlexander Motin };
22989b17223SAlexander Motin
23089b17223SAlexander Motin static g_raid_md_create_t g_raid_md_create_intel;
23189b17223SAlexander Motin static g_raid_md_taste_t g_raid_md_taste_intel;
23289b17223SAlexander Motin static g_raid_md_event_t g_raid_md_event_intel;
23389b17223SAlexander Motin static g_raid_md_ctl_t g_raid_md_ctl_intel;
23489b17223SAlexander Motin static g_raid_md_write_t g_raid_md_write_intel;
23589b17223SAlexander Motin static g_raid_md_fail_disk_t g_raid_md_fail_disk_intel;
23689b17223SAlexander Motin static g_raid_md_free_disk_t g_raid_md_free_disk_intel;
23726c538bcSAlexander Motin static g_raid_md_free_volume_t g_raid_md_free_volume_intel;
23889b17223SAlexander Motin static g_raid_md_free_t g_raid_md_free_intel;
23989b17223SAlexander Motin
24089b17223SAlexander Motin static kobj_method_t g_raid_md_intel_methods[] = {
24189b17223SAlexander Motin KOBJMETHOD(g_raid_md_create, g_raid_md_create_intel),
24289b17223SAlexander Motin KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_intel),
24389b17223SAlexander Motin KOBJMETHOD(g_raid_md_event, g_raid_md_event_intel),
24489b17223SAlexander Motin KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_intel),
24589b17223SAlexander Motin KOBJMETHOD(g_raid_md_write, g_raid_md_write_intel),
24689b17223SAlexander Motin KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_intel),
24789b17223SAlexander Motin KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_intel),
24826c538bcSAlexander Motin KOBJMETHOD(g_raid_md_free_volume, g_raid_md_free_volume_intel),
24989b17223SAlexander Motin KOBJMETHOD(g_raid_md_free, g_raid_md_free_intel),
25089b17223SAlexander Motin { 0, 0 }
25189b17223SAlexander Motin };
25289b17223SAlexander Motin
25389b17223SAlexander Motin static struct g_raid_md_class g_raid_md_intel_class = {
25489b17223SAlexander Motin "Intel",
25589b17223SAlexander Motin g_raid_md_intel_methods,
25689b17223SAlexander Motin sizeof(struct g_raid_md_intel_object),
257c89d2fbeSAlexander Motin .mdc_enable = 1,
25889b17223SAlexander Motin .mdc_priority = 100
25989b17223SAlexander Motin };
26089b17223SAlexander Motin
26189b17223SAlexander Motin static struct intel_raid_map *
intel_get_map(struct intel_raid_vol * mvol,int i)26289b17223SAlexander Motin intel_get_map(struct intel_raid_vol *mvol, int i)
26389b17223SAlexander Motin {
26489b17223SAlexander Motin struct intel_raid_map *mmap;
26589b17223SAlexander Motin
26689b17223SAlexander Motin if (i > (mvol->migr_state ? 1 : 0))
26789b17223SAlexander Motin return (NULL);
26889b17223SAlexander Motin mmap = &mvol->map[0];
26989b17223SAlexander Motin for (; i > 0; i--) {
27089b17223SAlexander Motin mmap = (struct intel_raid_map *)
27189b17223SAlexander Motin &mmap->disk_idx[mmap->total_disks];
27289b17223SAlexander Motin }
27389b17223SAlexander Motin return ((struct intel_raid_map *)mmap);
27489b17223SAlexander Motin }
27589b17223SAlexander Motin
27689b17223SAlexander Motin static struct intel_raid_vol *
intel_get_volume(struct intel_raid_conf * meta,int i)27789b17223SAlexander Motin intel_get_volume(struct intel_raid_conf *meta, int i)
27889b17223SAlexander Motin {
27989b17223SAlexander Motin struct intel_raid_vol *mvol;
28089b17223SAlexander Motin struct intel_raid_map *mmap;
28189b17223SAlexander Motin
28289b17223SAlexander Motin if (i > 1)
28389b17223SAlexander Motin return (NULL);
28489b17223SAlexander Motin mvol = (struct intel_raid_vol *)&meta->disk[meta->total_disks];
28589b17223SAlexander Motin for (; i > 0; i--) {
28689b17223SAlexander Motin mmap = intel_get_map(mvol, mvol->migr_state ? 1 : 0);
28789b17223SAlexander Motin mvol = (struct intel_raid_vol *)
28889b17223SAlexander Motin &mmap->disk_idx[mmap->total_disks];
28989b17223SAlexander Motin }
29089b17223SAlexander Motin return (mvol);
29189b17223SAlexander Motin }
29289b17223SAlexander Motin
293c1ad3fcfSJim Harris static off_t
intel_get_map_offset(struct intel_raid_map * mmap)294c1ad3fcfSJim Harris intel_get_map_offset(struct intel_raid_map *mmap)
295c1ad3fcfSJim Harris {
296c1ad3fcfSJim Harris off_t offset = (off_t)mmap->offset_hi << 32;
297c1ad3fcfSJim Harris
298c1ad3fcfSJim Harris offset += mmap->offset;
299c1ad3fcfSJim Harris return (offset);
300c1ad3fcfSJim Harris }
301c1ad3fcfSJim Harris
302c1ad3fcfSJim Harris static void
intel_set_map_offset(struct intel_raid_map * mmap,off_t offset)303c1ad3fcfSJim Harris intel_set_map_offset(struct intel_raid_map *mmap, off_t offset)
304c1ad3fcfSJim Harris {
305c1ad3fcfSJim Harris
306c1ad3fcfSJim Harris mmap->offset = offset & 0xffffffff;
307c1ad3fcfSJim Harris mmap->offset_hi = offset >> 32;
308c1ad3fcfSJim Harris }
309c1ad3fcfSJim Harris
310c1ad3fcfSJim Harris static off_t
intel_get_map_disk_sectors(struct intel_raid_map * mmap)311c1ad3fcfSJim Harris intel_get_map_disk_sectors(struct intel_raid_map *mmap)
312c1ad3fcfSJim Harris {
313c1ad3fcfSJim Harris off_t disk_sectors = (off_t)mmap->disk_sectors_hi << 32;
314c1ad3fcfSJim Harris
315c1ad3fcfSJim Harris disk_sectors += mmap->disk_sectors;
316c1ad3fcfSJim Harris return (disk_sectors);
317c1ad3fcfSJim Harris }
318c1ad3fcfSJim Harris
319c1ad3fcfSJim Harris static void
intel_set_map_disk_sectors(struct intel_raid_map * mmap,off_t disk_sectors)320c1ad3fcfSJim Harris intel_set_map_disk_sectors(struct intel_raid_map *mmap, off_t disk_sectors)
321c1ad3fcfSJim Harris {
322c1ad3fcfSJim Harris
323c1ad3fcfSJim Harris mmap->disk_sectors = disk_sectors & 0xffffffff;
324c1ad3fcfSJim Harris mmap->disk_sectors_hi = disk_sectors >> 32;
325c1ad3fcfSJim Harris }
326c1ad3fcfSJim Harris
327c1ad3fcfSJim Harris static void
intel_set_map_stripe_count(struct intel_raid_map * mmap,off_t stripe_count)328c1ad3fcfSJim Harris intel_set_map_stripe_count(struct intel_raid_map *mmap, off_t stripe_count)
329c1ad3fcfSJim Harris {
330c1ad3fcfSJim Harris
331c1ad3fcfSJim Harris mmap->stripe_count = stripe_count & 0xffffffff;
332c1ad3fcfSJim Harris mmap->stripe_count_hi = stripe_count >> 32;
333c1ad3fcfSJim Harris }
334c1ad3fcfSJim Harris
335c1ad3fcfSJim Harris static off_t
intel_get_disk_sectors(struct intel_raid_disk * disk)336c1ad3fcfSJim Harris intel_get_disk_sectors(struct intel_raid_disk *disk)
337c1ad3fcfSJim Harris {
338c1ad3fcfSJim Harris off_t sectors = (off_t)disk->sectors_hi << 32;
339c1ad3fcfSJim Harris
340c1ad3fcfSJim Harris sectors += disk->sectors;
341c1ad3fcfSJim Harris return (sectors);
342c1ad3fcfSJim Harris }
343c1ad3fcfSJim Harris
344c1ad3fcfSJim Harris static void
intel_set_disk_sectors(struct intel_raid_disk * disk,off_t sectors)345c1ad3fcfSJim Harris intel_set_disk_sectors(struct intel_raid_disk *disk, off_t sectors)
346c1ad3fcfSJim Harris {
347c1ad3fcfSJim Harris
348c1ad3fcfSJim Harris disk->sectors = sectors & 0xffffffff;
349c1ad3fcfSJim Harris disk->sectors_hi = sectors >> 32;
350c1ad3fcfSJim Harris }
351c1ad3fcfSJim Harris
352c1ad3fcfSJim Harris static off_t
intel_get_vol_curr_migr_unit(struct intel_raid_vol * vol)353c1ad3fcfSJim Harris intel_get_vol_curr_migr_unit(struct intel_raid_vol *vol)
354c1ad3fcfSJim Harris {
355c1ad3fcfSJim Harris off_t curr_migr_unit = (off_t)vol->curr_migr_unit_hi << 32;
356c1ad3fcfSJim Harris
357c1ad3fcfSJim Harris curr_migr_unit += vol->curr_migr_unit;
358c1ad3fcfSJim Harris return (curr_migr_unit);
359c1ad3fcfSJim Harris }
360c1ad3fcfSJim Harris
361c1ad3fcfSJim Harris static void
intel_set_vol_curr_migr_unit(struct intel_raid_vol * vol,off_t curr_migr_unit)362c1ad3fcfSJim Harris intel_set_vol_curr_migr_unit(struct intel_raid_vol *vol, off_t curr_migr_unit)
363c1ad3fcfSJim Harris {
364c1ad3fcfSJim Harris
365c1ad3fcfSJim Harris vol->curr_migr_unit = curr_migr_unit & 0xffffffff;
366c1ad3fcfSJim Harris vol->curr_migr_unit_hi = curr_migr_unit >> 32;
367c1ad3fcfSJim Harris }
368c1ad3fcfSJim Harris
36926f0f92fSAlexander Motin static char *
intel_status2str(int status)37026f0f92fSAlexander Motin intel_status2str(int status)
37126f0f92fSAlexander Motin {
37226f0f92fSAlexander Motin
37326f0f92fSAlexander Motin switch (status) {
37426f0f92fSAlexander Motin case INTEL_S_READY:
37526f0f92fSAlexander Motin return ("READY");
37626f0f92fSAlexander Motin case INTEL_S_UNINITIALIZED:
37726f0f92fSAlexander Motin return ("UNINITIALIZED");
37826f0f92fSAlexander Motin case INTEL_S_DEGRADED:
37926f0f92fSAlexander Motin return ("DEGRADED");
38026f0f92fSAlexander Motin case INTEL_S_FAILURE:
38126f0f92fSAlexander Motin return ("FAILURE");
38226f0f92fSAlexander Motin default:
38326f0f92fSAlexander Motin return ("UNKNOWN");
38426f0f92fSAlexander Motin }
38526f0f92fSAlexander Motin }
38626f0f92fSAlexander Motin
38726f0f92fSAlexander Motin static char *
intel_type2str(int type)38826f0f92fSAlexander Motin intel_type2str(int type)
38926f0f92fSAlexander Motin {
39026f0f92fSAlexander Motin
39126f0f92fSAlexander Motin switch (type) {
39226f0f92fSAlexander Motin case INTEL_T_RAID0:
39326f0f92fSAlexander Motin return ("RAID0");
39426f0f92fSAlexander Motin case INTEL_T_RAID1:
39526f0f92fSAlexander Motin return ("RAID1");
39626f0f92fSAlexander Motin case INTEL_T_RAID5:
39726f0f92fSAlexander Motin return ("RAID5");
39826f0f92fSAlexander Motin default:
39926f0f92fSAlexander Motin return ("UNKNOWN");
40026f0f92fSAlexander Motin }
40126f0f92fSAlexander Motin }
40226f0f92fSAlexander Motin
40326f0f92fSAlexander Motin static char *
intel_cngst2str(int cng_state)40426f0f92fSAlexander Motin intel_cngst2str(int cng_state)
40526f0f92fSAlexander Motin {
40626f0f92fSAlexander Motin
40726f0f92fSAlexander Motin switch (cng_state) {
40826f0f92fSAlexander Motin case INTEL_CNGST_UPDATED:
40926f0f92fSAlexander Motin return ("UPDATED");
41026f0f92fSAlexander Motin case INTEL_CNGST_NEEDS_UPDATE:
41126f0f92fSAlexander Motin return ("NEEDS_UPDATE");
41226f0f92fSAlexander Motin case INTEL_CNGST_MASTER_MISSING:
41326f0f92fSAlexander Motin return ("MASTER_MISSING");
41426f0f92fSAlexander Motin default:
41526f0f92fSAlexander Motin return ("UNKNOWN");
41626f0f92fSAlexander Motin }
41726f0f92fSAlexander Motin }
41826f0f92fSAlexander Motin
41926f0f92fSAlexander Motin static char *
intel_mt2str(int type)42026f0f92fSAlexander Motin intel_mt2str(int type)
42126f0f92fSAlexander Motin {
42226f0f92fSAlexander Motin
42326f0f92fSAlexander Motin switch (type) {
42426f0f92fSAlexander Motin case INTEL_MT_INIT:
42526f0f92fSAlexander Motin return ("INIT");
42626f0f92fSAlexander Motin case INTEL_MT_REBUILD:
42726f0f92fSAlexander Motin return ("REBUILD");
42826f0f92fSAlexander Motin case INTEL_MT_VERIFY:
42926f0f92fSAlexander Motin return ("VERIFY");
43026f0f92fSAlexander Motin case INTEL_MT_GEN_MIGR:
43126f0f92fSAlexander Motin return ("GEN_MIGR");
43226f0f92fSAlexander Motin case INTEL_MT_STATE_CHANGE:
43326f0f92fSAlexander Motin return ("STATE_CHANGE");
43426f0f92fSAlexander Motin case INTEL_MT_REPAIR:
43526f0f92fSAlexander Motin return ("REPAIR");
43626f0f92fSAlexander Motin default:
43726f0f92fSAlexander Motin return ("UNKNOWN");
43826f0f92fSAlexander Motin }
43926f0f92fSAlexander Motin }
44026f0f92fSAlexander Motin
44189b17223SAlexander Motin static void
g_raid_md_intel_print(struct intel_raid_conf * meta)44289b17223SAlexander Motin g_raid_md_intel_print(struct intel_raid_conf *meta)
44389b17223SAlexander Motin {
44489b17223SAlexander Motin struct intel_raid_vol *mvol;
44589b17223SAlexander Motin struct intel_raid_map *mmap;
44689b17223SAlexander Motin int i, j, k;
44789b17223SAlexander Motin
44889b17223SAlexander Motin if (g_raid_debug < 1)
44989b17223SAlexander Motin return;
45089b17223SAlexander Motin
45189b17223SAlexander Motin printf("********* ATA Intel MatrixRAID Metadata *********\n");
45289b17223SAlexander Motin printf("intel_id <%.24s>\n", meta->intel_id);
45389b17223SAlexander Motin printf("version <%.6s>\n", meta->version);
45489b17223SAlexander Motin printf("checksum 0x%08x\n", meta->checksum);
45589b17223SAlexander Motin printf("config_size 0x%08x\n", meta->config_size);
45689b17223SAlexander Motin printf("config_id 0x%08x\n", meta->config_id);
45789b17223SAlexander Motin printf("generation 0x%08x\n", meta->generation);
4584c95a241SAlexander Motin printf("error_log_size %d\n", meta->error_log_size);
45926f0f92fSAlexander Motin printf("attributes 0x%b\n", meta->attributes,
46026f0f92fSAlexander Motin "\020"
46126f0f92fSAlexander Motin "\001RAID0"
46226f0f92fSAlexander Motin "\002RAID1"
46326f0f92fSAlexander Motin "\003RAID10"
46426f0f92fSAlexander Motin "\004RAID1E"
46526f0f92fSAlexander Motin "\005RAID15"
46626f0f92fSAlexander Motin "\006RAIDCNG"
46726f0f92fSAlexander Motin "\007EXT_STRIP"
46826f0f92fSAlexander Motin "\032NVM_CACHE"
46926f0f92fSAlexander Motin "\0332TB_DISK"
47026f0f92fSAlexander Motin "\034BBM"
47126f0f92fSAlexander Motin "\035NVM_CACHE"
47226f0f92fSAlexander Motin "\0362TB"
47326f0f92fSAlexander Motin "\037PM"
47426f0f92fSAlexander Motin "\040CHECKSUM");
47589b17223SAlexander Motin printf("total_disks %u\n", meta->total_disks);
47689b17223SAlexander Motin printf("total_volumes %u\n", meta->total_volumes);
477511c69d9SAlexander Motin printf("error_log_pos %u\n", meta->error_log_pos);
478511c69d9SAlexander Motin printf("cache_size %u\n", meta->cache_size);
479511c69d9SAlexander Motin printf("orig_config_id 0x%08x\n", meta->orig_config_id);
480511c69d9SAlexander Motin printf("pwr_cycle_count %u\n", meta->pwr_cycle_count);
4814c95a241SAlexander Motin printf("bbm_log_size %u\n", meta->bbm_log_size);
48226f0f92fSAlexander Motin printf("Flags: S - Spare, A - Assigned, F - Failed, O - Online, D - Disabled\n");
483511c69d9SAlexander Motin printf("DISK# serial disk_sectors disk_sectors_hi disk_id flags owner\n");
48489b17223SAlexander Motin for (i = 0; i < meta->total_disks; i++ ) {
48526f0f92fSAlexander Motin printf(" %d <%.16s> %u %u 0x%08x 0x%b %08x\n", i,
48689b17223SAlexander Motin meta->disk[i].serial, meta->disk[i].sectors,
487511c69d9SAlexander Motin meta->disk[i].sectors_hi, meta->disk[i].id,
48826f0f92fSAlexander Motin meta->disk[i].flags, "\20\01S\02A\03F\04O\05D",
48926f0f92fSAlexander Motin meta->disk[i].owner_cfg_num);
49089b17223SAlexander Motin }
49189b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
49289b17223SAlexander Motin mvol = intel_get_volume(meta, i);
49389b17223SAlexander Motin printf(" ****** Volume %d ******\n", i);
49489b17223SAlexander Motin printf(" name %.16s\n", mvol->name);
49589b17223SAlexander Motin printf(" total_sectors %ju\n", mvol->total_sectors);
49626f0f92fSAlexander Motin printf(" state 0x%b\n", mvol->state,
49726f0f92fSAlexander Motin "\020"
49826f0f92fSAlexander Motin "\001BOOTABLE"
49926f0f92fSAlexander Motin "\002BOOT_DEVICE"
50026f0f92fSAlexander Motin "\003READ_COALESCING"
50126f0f92fSAlexander Motin "\004WRITE_COALESCING"
50226f0f92fSAlexander Motin "\005LAST_SHUTDOWN_DIRTY"
50326f0f92fSAlexander Motin "\006HIDDEN_AT_BOOT"
50426f0f92fSAlexander Motin "\007CURRENTLY_HIDDEN"
50526f0f92fSAlexander Motin "\010VERIFY_AND_FIX"
50626f0f92fSAlexander Motin "\011MAP_STATE_UNINIT"
50726f0f92fSAlexander Motin "\012NO_AUTO_RECOVERY"
50826f0f92fSAlexander Motin "\013CLONE_N_GO"
50926f0f92fSAlexander Motin "\014CLONE_MAN_SYNC"
51026f0f92fSAlexander Motin "\015CNG_MASTER_DISK_NUM");
51189b17223SAlexander Motin printf(" reserved %u\n", mvol->reserved);
51226c538bcSAlexander Motin printf(" migr_priority %u\n", mvol->migr_priority);
51326c538bcSAlexander Motin printf(" num_sub_vols %u\n", mvol->num_sub_vols);
51426c538bcSAlexander Motin printf(" tid %u\n", mvol->tid);
51526c538bcSAlexander Motin printf(" cng_master_disk %u\n", mvol->cng_master_disk);
51626c538bcSAlexander Motin printf(" cache_policy %u\n", mvol->cache_policy);
51726f0f92fSAlexander Motin printf(" cng_state %u (%s)\n", mvol->cng_state,
51826f0f92fSAlexander Motin intel_cngst2str(mvol->cng_state));
51926c538bcSAlexander Motin printf(" cng_sub_state %u\n", mvol->cng_sub_state);
52089b17223SAlexander Motin printf(" curr_migr_unit %u\n", mvol->curr_migr_unit);
521c1ad3fcfSJim Harris printf(" curr_migr_unit_hi %u\n", mvol->curr_migr_unit_hi);
52289b17223SAlexander Motin printf(" checkpoint_id %u\n", mvol->checkpoint_id);
52389b17223SAlexander Motin printf(" migr_state %u\n", mvol->migr_state);
52426f0f92fSAlexander Motin printf(" migr_type %u (%s)\n", mvol->migr_type,
52526f0f92fSAlexander Motin intel_mt2str(mvol->migr_type));
52689b17223SAlexander Motin printf(" dirty %u\n", mvol->dirty);
527511c69d9SAlexander Motin printf(" fs_state %u\n", mvol->fs_state);
528511c69d9SAlexander Motin printf(" verify_errors %u\n", mvol->verify_errors);
529511c69d9SAlexander Motin printf(" bad_blocks %u\n", mvol->bad_blocks);
53089b17223SAlexander Motin
53189b17223SAlexander Motin for (j = 0; j < (mvol->migr_state ? 2 : 1); j++) {
53289b17223SAlexander Motin printf(" *** Map %d ***\n", j);
53389b17223SAlexander Motin mmap = intel_get_map(mvol, j);
53489b17223SAlexander Motin printf(" offset %u\n", mmap->offset);
535c1ad3fcfSJim Harris printf(" offset_hi %u\n", mmap->offset_hi);
53689b17223SAlexander Motin printf(" disk_sectors %u\n", mmap->disk_sectors);
537c1ad3fcfSJim Harris printf(" disk_sectors_hi %u\n", mmap->disk_sectors_hi);
53889b17223SAlexander Motin printf(" stripe_count %u\n", mmap->stripe_count);
539c1ad3fcfSJim Harris printf(" stripe_count_hi %u\n", mmap->stripe_count_hi);
54089b17223SAlexander Motin printf(" strip_sectors %u\n", mmap->strip_sectors);
54126f0f92fSAlexander Motin printf(" status %u (%s)\n", mmap->status,
54226f0f92fSAlexander Motin intel_status2str(mmap->status));
54326f0f92fSAlexander Motin printf(" type %u (%s)\n", mmap->type,
54426f0f92fSAlexander Motin intel_type2str(mmap->type));
54589b17223SAlexander Motin printf(" total_disks %u\n", mmap->total_disks);
54689b17223SAlexander Motin printf(" total_domains %u\n", mmap->total_domains);
54789b17223SAlexander Motin printf(" failed_disk_num %u\n", mmap->failed_disk_num);
54889b17223SAlexander Motin printf(" ddf %u\n", mmap->ddf);
54989b17223SAlexander Motin printf(" disk_idx ");
55089b17223SAlexander Motin for (k = 0; k < mmap->total_disks; k++)
55189b17223SAlexander Motin printf(" 0x%08x", mmap->disk_idx[k]);
55289b17223SAlexander Motin printf("\n");
55389b17223SAlexander Motin }
55489b17223SAlexander Motin }
55589b17223SAlexander Motin printf("=================================================\n");
55689b17223SAlexander Motin }
55789b17223SAlexander Motin
55889b17223SAlexander Motin static struct intel_raid_conf *
intel_meta_copy(struct intel_raid_conf * meta)55989b17223SAlexander Motin intel_meta_copy(struct intel_raid_conf *meta)
56089b17223SAlexander Motin {
56189b17223SAlexander Motin struct intel_raid_conf *nmeta;
56289b17223SAlexander Motin
56389b17223SAlexander Motin nmeta = malloc(meta->config_size, M_MD_INTEL, M_WAITOK);
56489b17223SAlexander Motin memcpy(nmeta, meta, meta->config_size);
56589b17223SAlexander Motin return (nmeta);
56689b17223SAlexander Motin }
56789b17223SAlexander Motin
56889b17223SAlexander Motin static int
intel_meta_find_disk(struct intel_raid_conf * meta,char * serial)56989b17223SAlexander Motin intel_meta_find_disk(struct intel_raid_conf *meta, char *serial)
57089b17223SAlexander Motin {
57189b17223SAlexander Motin int pos;
57289b17223SAlexander Motin
57389b17223SAlexander Motin for (pos = 0; pos < meta->total_disks; pos++) {
57489b17223SAlexander Motin if (strncmp(meta->disk[pos].serial,
57589b17223SAlexander Motin serial, INTEL_SERIAL_LEN) == 0)
57689b17223SAlexander Motin return (pos);
57789b17223SAlexander Motin }
57889b17223SAlexander Motin return (-1);
57989b17223SAlexander Motin }
58089b17223SAlexander Motin
58189b17223SAlexander Motin static struct intel_raid_conf *
intel_meta_read(struct g_consumer * cp)58289b17223SAlexander Motin intel_meta_read(struct g_consumer *cp)
58389b17223SAlexander Motin {
58489b17223SAlexander Motin struct g_provider *pp;
58589b17223SAlexander Motin struct intel_raid_conf *meta;
58689b17223SAlexander Motin struct intel_raid_vol *mvol;
5874c95a241SAlexander Motin struct intel_raid_map *mmap, *mmap1;
58889b17223SAlexander Motin char *buf;
58989b17223SAlexander Motin int error, i, j, k, left, size;
59089b17223SAlexander Motin uint32_t checksum, *ptr;
59189b17223SAlexander Motin
59289b17223SAlexander Motin pp = cp->provider;
5939e9ba9c7SMark Johnston if (pp->sectorsize < sizeof(*meta))
5949e9ba9c7SMark Johnston return (NULL);
59589b17223SAlexander Motin /* Read the anchor sector. */
59689b17223SAlexander Motin buf = g_read_data(cp,
59789b17223SAlexander Motin pp->mediasize - pp->sectorsize * 2, pp->sectorsize, &error);
59889b17223SAlexander Motin if (buf == NULL) {
59989b17223SAlexander Motin G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).",
60089b17223SAlexander Motin pp->name, error);
60189b17223SAlexander Motin return (NULL);
60289b17223SAlexander Motin }
60389b17223SAlexander Motin meta = (struct intel_raid_conf *)buf;
60489b17223SAlexander Motin
60589b17223SAlexander Motin /* Check if this is an Intel RAID struct */
60689b17223SAlexander Motin if (strncmp(meta->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) {
60789b17223SAlexander Motin G_RAID_DEBUG(1, "Intel signature check failed on %s", pp->name);
60889b17223SAlexander Motin g_free(buf);
60989b17223SAlexander Motin return (NULL);
61089b17223SAlexander Motin }
61189b17223SAlexander Motin if (meta->config_size > 65536 ||
61289b17223SAlexander Motin meta->config_size < sizeof(struct intel_raid_conf)) {
61389b17223SAlexander Motin G_RAID_DEBUG(1, "Intel metadata size looks wrong: %d",
61489b17223SAlexander Motin meta->config_size);
61589b17223SAlexander Motin g_free(buf);
61689b17223SAlexander Motin return (NULL);
61789b17223SAlexander Motin }
61889b17223SAlexander Motin size = meta->config_size;
61989b17223SAlexander Motin meta = malloc(size, M_MD_INTEL, M_WAITOK);
62089b17223SAlexander Motin memcpy(meta, buf, min(size, pp->sectorsize));
62189b17223SAlexander Motin g_free(buf);
62289b17223SAlexander Motin
62389b17223SAlexander Motin /* Read all the rest, if needed. */
62489b17223SAlexander Motin if (meta->config_size > pp->sectorsize) {
62589b17223SAlexander Motin left = (meta->config_size - 1) / pp->sectorsize;
62689b17223SAlexander Motin buf = g_read_data(cp,
62789b17223SAlexander Motin pp->mediasize - pp->sectorsize * (2 + left),
62889b17223SAlexander Motin pp->sectorsize * left, &error);
62989b17223SAlexander Motin if (buf == NULL) {
63089b17223SAlexander Motin G_RAID_DEBUG(1, "Cannot read remaining metadata"
63189b17223SAlexander Motin " part from %s (error=%d).",
63289b17223SAlexander Motin pp->name, error);
63389b17223SAlexander Motin free(meta, M_MD_INTEL);
63489b17223SAlexander Motin return (NULL);
63589b17223SAlexander Motin }
63689b17223SAlexander Motin memcpy(((char *)meta) + pp->sectorsize, buf,
63789b17223SAlexander Motin pp->sectorsize * left);
63889b17223SAlexander Motin g_free(buf);
63989b17223SAlexander Motin }
64089b17223SAlexander Motin
64189b17223SAlexander Motin /* Check metadata checksum. */
64289b17223SAlexander Motin for (checksum = 0, ptr = (uint32_t *)meta, i = 0;
64389b17223SAlexander Motin i < (meta->config_size / sizeof(uint32_t)); i++) {
64489b17223SAlexander Motin checksum += *ptr++;
64589b17223SAlexander Motin }
64689b17223SAlexander Motin checksum -= meta->checksum;
64789b17223SAlexander Motin if (checksum != meta->checksum) {
64889b17223SAlexander Motin G_RAID_DEBUG(1, "Intel checksum check failed on %s", pp->name);
64989b17223SAlexander Motin free(meta, M_MD_INTEL);
65089b17223SAlexander Motin return (NULL);
65189b17223SAlexander Motin }
65289b17223SAlexander Motin
65389b17223SAlexander Motin /* Validate metadata size. */
65489b17223SAlexander Motin size = sizeof(struct intel_raid_conf) +
65589b17223SAlexander Motin sizeof(struct intel_raid_disk) * (meta->total_disks - 1) +
65689b17223SAlexander Motin sizeof(struct intel_raid_vol) * meta->total_volumes;
65789b17223SAlexander Motin if (size > meta->config_size) {
65889b17223SAlexander Motin badsize:
65989b17223SAlexander Motin G_RAID_DEBUG(1, "Intel metadata size incorrect %d < %d",
66089b17223SAlexander Motin meta->config_size, size);
66189b17223SAlexander Motin free(meta, M_MD_INTEL);
66289b17223SAlexander Motin return (NULL);
66389b17223SAlexander Motin }
66489b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
66589b17223SAlexander Motin mvol = intel_get_volume(meta, i);
66689b17223SAlexander Motin mmap = intel_get_map(mvol, 0);
66789b17223SAlexander Motin size += 4 * (mmap->total_disks - 1);
66889b17223SAlexander Motin if (size > meta->config_size)
66989b17223SAlexander Motin goto badsize;
67089b17223SAlexander Motin if (mvol->migr_state) {
67189b17223SAlexander Motin size += sizeof(struct intel_raid_map);
67289b17223SAlexander Motin if (size > meta->config_size)
67389b17223SAlexander Motin goto badsize;
67489b17223SAlexander Motin mmap = intel_get_map(mvol, 1);
67589b17223SAlexander Motin size += 4 * (mmap->total_disks - 1);
67689b17223SAlexander Motin if (size > meta->config_size)
67789b17223SAlexander Motin goto badsize;
67889b17223SAlexander Motin }
67989b17223SAlexander Motin }
68089b17223SAlexander Motin
6814c95a241SAlexander Motin g_raid_md_intel_print(meta);
6824c95a241SAlexander Motin
683f9462b9bSAlexander Motin if (strncmp(meta->version, INTEL_VERSION_1300, 6) > 0) {
684f9462b9bSAlexander Motin G_RAID_DEBUG(1, "Intel unsupported version: '%.6s'",
685f9462b9bSAlexander Motin meta->version);
686f9462b9bSAlexander Motin free(meta, M_MD_INTEL);
687f9462b9bSAlexander Motin return (NULL);
688f9462b9bSAlexander Motin }
689f9462b9bSAlexander Motin
690f9462b9bSAlexander Motin if (strncmp(meta->version, INTEL_VERSION_1300, 6) >= 0 &&
691f9462b9bSAlexander Motin (meta->attributes & ~INTEL_ATTR_SUPPORTED) != 0) {
692f9462b9bSAlexander Motin G_RAID_DEBUG(1, "Intel unsupported attributes: 0x%08x",
693f9462b9bSAlexander Motin meta->attributes & ~INTEL_ATTR_SUPPORTED);
694f9462b9bSAlexander Motin free(meta, M_MD_INTEL);
695f9462b9bSAlexander Motin return (NULL);
696f9462b9bSAlexander Motin }
697f9462b9bSAlexander Motin
69889b17223SAlexander Motin /* Validate disk indexes. */
69989b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
70089b17223SAlexander Motin mvol = intel_get_volume(meta, i);
70189b17223SAlexander Motin for (j = 0; j < (mvol->migr_state ? 2 : 1); j++) {
70289b17223SAlexander Motin mmap = intel_get_map(mvol, j);
70389b17223SAlexander Motin for (k = 0; k < mmap->total_disks; k++) {
70489b17223SAlexander Motin if ((mmap->disk_idx[k] & INTEL_DI_IDX) >
70589b17223SAlexander Motin meta->total_disks) {
70689b17223SAlexander Motin G_RAID_DEBUG(1, "Intel metadata disk"
70789b17223SAlexander Motin " index %d too big (>%d)",
70889b17223SAlexander Motin mmap->disk_idx[k] & INTEL_DI_IDX,
70989b17223SAlexander Motin meta->total_disks);
71089b17223SAlexander Motin free(meta, M_MD_INTEL);
71189b17223SAlexander Motin return (NULL);
71289b17223SAlexander Motin }
71389b17223SAlexander Motin }
71489b17223SAlexander Motin }
71589b17223SAlexander Motin }
71689b17223SAlexander Motin
71789b17223SAlexander Motin /* Validate migration types. */
71889b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
71989b17223SAlexander Motin mvol = intel_get_volume(meta, i);
7204c95a241SAlexander Motin /* Deny unknown migration types. */
72189b17223SAlexander Motin if (mvol->migr_state &&
72289b17223SAlexander Motin mvol->migr_type != INTEL_MT_INIT &&
72389b17223SAlexander Motin mvol->migr_type != INTEL_MT_REBUILD &&
72489b17223SAlexander Motin mvol->migr_type != INTEL_MT_VERIFY &&
7254c95a241SAlexander Motin mvol->migr_type != INTEL_MT_GEN_MIGR &&
72689b17223SAlexander Motin mvol->migr_type != INTEL_MT_REPAIR) {
72789b17223SAlexander Motin G_RAID_DEBUG(1, "Intel metadata has unsupported"
72889b17223SAlexander Motin " migration type %d", mvol->migr_type);
72989b17223SAlexander Motin free(meta, M_MD_INTEL);
73089b17223SAlexander Motin return (NULL);
73189b17223SAlexander Motin }
7324c95a241SAlexander Motin /* Deny general migrations except SINGLE->RAID1. */
7334c95a241SAlexander Motin if (mvol->migr_state &&
7344c95a241SAlexander Motin mvol->migr_type == INTEL_MT_GEN_MIGR) {
7354c95a241SAlexander Motin mmap = intel_get_map(mvol, 0);
7364c95a241SAlexander Motin mmap1 = intel_get_map(mvol, 1);
7374c95a241SAlexander Motin if (mmap1->total_disks != 1 ||
7384c95a241SAlexander Motin mmap->type != INTEL_T_RAID1 ||
7394c95a241SAlexander Motin mmap->total_disks != 2 ||
7404c95a241SAlexander Motin mmap->offset != mmap1->offset ||
7414c95a241SAlexander Motin mmap->disk_sectors != mmap1->disk_sectors ||
7424c95a241SAlexander Motin mmap->total_domains != mmap->total_disks ||
7434c95a241SAlexander Motin mmap->offset_hi != mmap1->offset_hi ||
7444c95a241SAlexander Motin mmap->disk_sectors_hi != mmap1->disk_sectors_hi ||
7454c95a241SAlexander Motin (mmap->disk_idx[0] != mmap1->disk_idx[0] &&
7464c95a241SAlexander Motin mmap->disk_idx[0] != mmap1->disk_idx[1])) {
7474c95a241SAlexander Motin G_RAID_DEBUG(1, "Intel metadata has unsupported"
7484c95a241SAlexander Motin " variant of general migration");
7494c95a241SAlexander Motin free(meta, M_MD_INTEL);
7504c95a241SAlexander Motin return (NULL);
7514c95a241SAlexander Motin }
7524c95a241SAlexander Motin }
75389b17223SAlexander Motin }
75489b17223SAlexander Motin
75589b17223SAlexander Motin return (meta);
75689b17223SAlexander Motin }
75789b17223SAlexander Motin
75889b17223SAlexander Motin static int
intel_meta_write(struct g_consumer * cp,struct intel_raid_conf * meta)75989b17223SAlexander Motin intel_meta_write(struct g_consumer *cp, struct intel_raid_conf *meta)
76089b17223SAlexander Motin {
76189b17223SAlexander Motin struct g_provider *pp;
76289b17223SAlexander Motin char *buf;
76389b17223SAlexander Motin int error, i, sectors;
76489b17223SAlexander Motin uint32_t checksum, *ptr;
76589b17223SAlexander Motin
76689b17223SAlexander Motin pp = cp->provider;
76789b17223SAlexander Motin
76889b17223SAlexander Motin /* Recalculate checksum for case if metadata were changed. */
76989b17223SAlexander Motin meta->checksum = 0;
77089b17223SAlexander Motin for (checksum = 0, ptr = (uint32_t *)meta, i = 0;
77189b17223SAlexander Motin i < (meta->config_size / sizeof(uint32_t)); i++) {
77289b17223SAlexander Motin checksum += *ptr++;
77389b17223SAlexander Motin }
77489b17223SAlexander Motin meta->checksum = checksum;
77589b17223SAlexander Motin
77689b17223SAlexander Motin /* Create and fill buffer. */
77755e0987aSPedro F. Giffuni sectors = howmany(meta->config_size, pp->sectorsize);
77889b17223SAlexander Motin buf = malloc(sectors * pp->sectorsize, M_MD_INTEL, M_WAITOK | M_ZERO);
77989b17223SAlexander Motin if (sectors > 1) {
78089b17223SAlexander Motin memcpy(buf, ((char *)meta) + pp->sectorsize,
78189b17223SAlexander Motin (sectors - 1) * pp->sectorsize);
78289b17223SAlexander Motin }
78389b17223SAlexander Motin memcpy(buf + (sectors - 1) * pp->sectorsize, meta, pp->sectorsize);
78489b17223SAlexander Motin
78589b17223SAlexander Motin error = g_write_data(cp,
78689b17223SAlexander Motin pp->mediasize - pp->sectorsize * (1 + sectors),
78789b17223SAlexander Motin buf, pp->sectorsize * sectors);
78889b17223SAlexander Motin if (error != 0) {
78989b17223SAlexander Motin G_RAID_DEBUG(1, "Cannot write metadata to %s (error=%d).",
79089b17223SAlexander Motin pp->name, error);
79189b17223SAlexander Motin }
79289b17223SAlexander Motin
79389b17223SAlexander Motin free(buf, M_MD_INTEL);
79489b17223SAlexander Motin return (error);
79589b17223SAlexander Motin }
79689b17223SAlexander Motin
79789b17223SAlexander Motin static int
intel_meta_erase(struct g_consumer * cp)79889b17223SAlexander Motin intel_meta_erase(struct g_consumer *cp)
79989b17223SAlexander Motin {
80089b17223SAlexander Motin struct g_provider *pp;
80189b17223SAlexander Motin char *buf;
80289b17223SAlexander Motin int error;
80389b17223SAlexander Motin
80489b17223SAlexander Motin pp = cp->provider;
80589b17223SAlexander Motin buf = malloc(pp->sectorsize, M_MD_INTEL, M_WAITOK | M_ZERO);
80689b17223SAlexander Motin error = g_write_data(cp,
80789b17223SAlexander Motin pp->mediasize - 2 * pp->sectorsize,
80889b17223SAlexander Motin buf, pp->sectorsize);
80989b17223SAlexander Motin if (error != 0) {
81089b17223SAlexander Motin G_RAID_DEBUG(1, "Cannot erase metadata on %s (error=%d).",
81189b17223SAlexander Motin pp->name, error);
81289b17223SAlexander Motin }
81389b17223SAlexander Motin free(buf, M_MD_INTEL);
81489b17223SAlexander Motin return (error);
81589b17223SAlexander Motin }
81689b17223SAlexander Motin
81789b17223SAlexander Motin static int
intel_meta_write_spare(struct g_consumer * cp,struct intel_raid_disk * d)81889b17223SAlexander Motin intel_meta_write_spare(struct g_consumer *cp, struct intel_raid_disk *d)
81989b17223SAlexander Motin {
82089b17223SAlexander Motin struct intel_raid_conf *meta;
82189b17223SAlexander Motin int error;
82289b17223SAlexander Motin
82389b17223SAlexander Motin /* Fill anchor and single disk. */
82489b17223SAlexander Motin meta = malloc(INTEL_MAX_MD_SIZE(1), M_MD_INTEL, M_WAITOK | M_ZERO);
82563607675SAlexander Motin memcpy(&meta->intel_id[0], INTEL_MAGIC, sizeof(INTEL_MAGIC) - 1);
82689b17223SAlexander Motin memcpy(&meta->version[0], INTEL_VERSION_1000,
82763607675SAlexander Motin sizeof(INTEL_VERSION_1000) - 1);
82889b17223SAlexander Motin meta->config_size = INTEL_MAX_MD_SIZE(1);
8294c10c25eSAlexander Motin meta->config_id = meta->orig_config_id = arc4random();
83089b17223SAlexander Motin meta->generation = 1;
83189b17223SAlexander Motin meta->total_disks = 1;
83289b17223SAlexander Motin meta->disk[0] = *d;
83389b17223SAlexander Motin error = intel_meta_write(cp, meta);
83489b17223SAlexander Motin free(meta, M_MD_INTEL);
83589b17223SAlexander Motin return (error);
83689b17223SAlexander Motin }
83789b17223SAlexander Motin
83889b17223SAlexander Motin static struct g_raid_disk *
g_raid_md_intel_get_disk(struct g_raid_softc * sc,int id)83989b17223SAlexander Motin g_raid_md_intel_get_disk(struct g_raid_softc *sc, int id)
84089b17223SAlexander Motin {
84189b17223SAlexander Motin struct g_raid_disk *disk;
84289b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
84389b17223SAlexander Motin
84489b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
84589b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
84689b17223SAlexander Motin if (pd->pd_disk_pos == id)
84789b17223SAlexander Motin break;
84889b17223SAlexander Motin }
84989b17223SAlexander Motin return (disk);
85089b17223SAlexander Motin }
85189b17223SAlexander Motin
85289b17223SAlexander Motin static int
g_raid_md_intel_supported(int level,int qual,int disks,int force)85389b17223SAlexander Motin g_raid_md_intel_supported(int level, int qual, int disks, int force)
85489b17223SAlexander Motin {
85589b17223SAlexander Motin
85689b17223SAlexander Motin switch (level) {
85789b17223SAlexander Motin case G_RAID_VOLUME_RL_RAID0:
85889b17223SAlexander Motin if (disks < 1)
85989b17223SAlexander Motin return (0);
86089b17223SAlexander Motin if (!force && (disks < 2 || disks > 6))
86189b17223SAlexander Motin return (0);
86289b17223SAlexander Motin break;
86389b17223SAlexander Motin case G_RAID_VOLUME_RL_RAID1:
86489b17223SAlexander Motin if (disks < 1)
86589b17223SAlexander Motin return (0);
86689b17223SAlexander Motin if (!force && (disks != 2))
86789b17223SAlexander Motin return (0);
86889b17223SAlexander Motin break;
86989b17223SAlexander Motin case G_RAID_VOLUME_RL_RAID1E:
87089b17223SAlexander Motin if (disks < 2)
87189b17223SAlexander Motin return (0);
87289b17223SAlexander Motin if (!force && (disks != 4))
87389b17223SAlexander Motin return (0);
87489b17223SAlexander Motin break;
87589b17223SAlexander Motin case G_RAID_VOLUME_RL_RAID5:
87689b17223SAlexander Motin if (disks < 3)
87789b17223SAlexander Motin return (0);
87889b17223SAlexander Motin if (!force && disks > 6)
87989b17223SAlexander Motin return (0);
880fc1de960SAlexander Motin if (qual != G_RAID_VOLUME_RLQ_R5LA)
881fc1de960SAlexander Motin return (0);
88289b17223SAlexander Motin break;
88389b17223SAlexander Motin default:
88489b17223SAlexander Motin return (0);
88589b17223SAlexander Motin }
886fc1de960SAlexander Motin if (level != G_RAID_VOLUME_RL_RAID5 && qual != G_RAID_VOLUME_RLQ_NONE)
88789b17223SAlexander Motin return (0);
88889b17223SAlexander Motin return (1);
88989b17223SAlexander Motin }
89089b17223SAlexander Motin
89189b17223SAlexander Motin static struct g_raid_volume *
g_raid_md_intel_get_volume(struct g_raid_softc * sc,int id)89289b17223SAlexander Motin g_raid_md_intel_get_volume(struct g_raid_softc *sc, int id)
89389b17223SAlexander Motin {
89489b17223SAlexander Motin struct g_raid_volume *mvol;
89526c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
89689b17223SAlexander Motin
89789b17223SAlexander Motin TAILQ_FOREACH(mvol, &sc->sc_volumes, v_next) {
89826c538bcSAlexander Motin pv = mvol->v_md_data;
89926c538bcSAlexander Motin if (pv->pv_volume_pos == id)
90089b17223SAlexander Motin break;
90189b17223SAlexander Motin }
90289b17223SAlexander Motin return (mvol);
90389b17223SAlexander Motin }
90489b17223SAlexander Motin
90589b17223SAlexander Motin static int
g_raid_md_intel_start_disk(struct g_raid_disk * disk)90689b17223SAlexander Motin g_raid_md_intel_start_disk(struct g_raid_disk *disk)
90789b17223SAlexander Motin {
90889b17223SAlexander Motin struct g_raid_softc *sc;
90989b17223SAlexander Motin struct g_raid_subdisk *sd, *tmpsd;
91089b17223SAlexander Motin struct g_raid_disk *olddisk, *tmpdisk;
91189b17223SAlexander Motin struct g_raid_md_object *md;
91289b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
91326c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
91489b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd, *oldpd;
91589b17223SAlexander Motin struct intel_raid_conf *meta;
91689b17223SAlexander Motin struct intel_raid_vol *mvol;
91789b17223SAlexander Motin struct intel_raid_map *mmap0, *mmap1;
918865aea63SAlexander Motin int disk_pos, resurrection = 0, migr_global, i;
91989b17223SAlexander Motin
92089b17223SAlexander Motin sc = disk->d_softc;
92189b17223SAlexander Motin md = sc->sc_md;
92289b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
92389b17223SAlexander Motin meta = mdi->mdio_meta;
92489b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
92589b17223SAlexander Motin olddisk = NULL;
92689b17223SAlexander Motin
92728323addSBryan Drewery /* Find disk position in metadata by its serial. */
92889b17223SAlexander Motin disk_pos = intel_meta_find_disk(meta, pd->pd_disk_meta.serial);
92989b17223SAlexander Motin if (disk_pos < 0) {
93089b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "Unknown, probably new or stale disk");
93189b17223SAlexander Motin /* Failed stale disk is useless for us. */
932b99586c2SAlexander Motin if ((pd->pd_disk_meta.flags & INTEL_F_FAILED) &&
933b99586c2SAlexander Motin !(pd->pd_disk_meta.flags & INTEL_F_DISABLED)) {
93489b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE_FAILED);
93589b17223SAlexander Motin return (0);
93689b17223SAlexander Motin }
93789b17223SAlexander Motin /* If we are in the start process, that's all for now. */
93889b17223SAlexander Motin if (!mdi->mdio_started)
93989b17223SAlexander Motin goto nofit;
94089b17223SAlexander Motin /*
94189b17223SAlexander Motin * If we have already started - try to get use of the disk.
94289b17223SAlexander Motin * Try to replace OFFLINE disks first, then FAILED.
94389b17223SAlexander Motin */
94489b17223SAlexander Motin TAILQ_FOREACH(tmpdisk, &sc->sc_disks, d_next) {
94589b17223SAlexander Motin if (tmpdisk->d_state != G_RAID_DISK_S_OFFLINE &&
94689b17223SAlexander Motin tmpdisk->d_state != G_RAID_DISK_S_FAILED)
94789b17223SAlexander Motin continue;
94889b17223SAlexander Motin /* Make sure this disk is big enough. */
94989b17223SAlexander Motin TAILQ_FOREACH(sd, &tmpdisk->d_subdisks, sd_next) {
950c1ad3fcfSJim Harris off_t disk_sectors =
951c1ad3fcfSJim Harris intel_get_disk_sectors(&pd->pd_disk_meta);
952c1ad3fcfSJim Harris
95389b17223SAlexander Motin if (sd->sd_offset + sd->sd_size + 4096 >
954c1ad3fcfSJim Harris disk_sectors * 512) {
95589b17223SAlexander Motin G_RAID_DEBUG1(1, sc,
95689b17223SAlexander Motin "Disk too small (%llu < %llu)",
957c1ad3fcfSJim Harris (unsigned long long)
958c1ad3fcfSJim Harris disk_sectors * 512,
95989b17223SAlexander Motin (unsigned long long)
96089b17223SAlexander Motin sd->sd_offset + sd->sd_size + 4096);
96189b17223SAlexander Motin break;
96289b17223SAlexander Motin }
96389b17223SAlexander Motin }
96489b17223SAlexander Motin if (sd != NULL)
96589b17223SAlexander Motin continue;
96689b17223SAlexander Motin if (tmpdisk->d_state == G_RAID_DISK_S_OFFLINE) {
96789b17223SAlexander Motin olddisk = tmpdisk;
96889b17223SAlexander Motin break;
96989b17223SAlexander Motin } else if (olddisk == NULL)
97089b17223SAlexander Motin olddisk = tmpdisk;
97189b17223SAlexander Motin }
97289b17223SAlexander Motin if (olddisk == NULL) {
97389b17223SAlexander Motin nofit:
97489b17223SAlexander Motin if (pd->pd_disk_meta.flags & INTEL_F_SPARE) {
97589b17223SAlexander Motin g_raid_change_disk_state(disk,
97689b17223SAlexander Motin G_RAID_DISK_S_SPARE);
97789b17223SAlexander Motin return (1);
97889b17223SAlexander Motin } else {
97989b17223SAlexander Motin g_raid_change_disk_state(disk,
98089b17223SAlexander Motin G_RAID_DISK_S_STALE);
98189b17223SAlexander Motin return (0);
98289b17223SAlexander Motin }
98389b17223SAlexander Motin }
98489b17223SAlexander Motin oldpd = (struct g_raid_md_intel_perdisk *)olddisk->d_md_data;
98589b17223SAlexander Motin disk_pos = oldpd->pd_disk_pos;
98689b17223SAlexander Motin resurrection = 1;
98789b17223SAlexander Motin }
98889b17223SAlexander Motin
98989b17223SAlexander Motin if (olddisk == NULL) {
99089b17223SAlexander Motin /* Find placeholder by position. */
99189b17223SAlexander Motin olddisk = g_raid_md_intel_get_disk(sc, disk_pos);
99289b17223SAlexander Motin if (olddisk == NULL)
99389b17223SAlexander Motin panic("No disk at position %d!", disk_pos);
99489b17223SAlexander Motin if (olddisk->d_state != G_RAID_DISK_S_OFFLINE) {
9956bc3fe5fSPedro F. Giffuni G_RAID_DEBUG1(1, sc, "More than one disk for pos %d",
99689b17223SAlexander Motin disk_pos);
99789b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_STALE);
99889b17223SAlexander Motin return (0);
99989b17223SAlexander Motin }
100089b17223SAlexander Motin oldpd = (struct g_raid_md_intel_perdisk *)olddisk->d_md_data;
100189b17223SAlexander Motin }
100289b17223SAlexander Motin
100389b17223SAlexander Motin /* Replace failed disk or placeholder with new disk. */
100489b17223SAlexander Motin TAILQ_FOREACH_SAFE(sd, &olddisk->d_subdisks, sd_next, tmpsd) {
100589b17223SAlexander Motin TAILQ_REMOVE(&olddisk->d_subdisks, sd, sd_next);
100689b17223SAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
100789b17223SAlexander Motin sd->sd_disk = disk;
100889b17223SAlexander Motin }
100989b17223SAlexander Motin oldpd->pd_disk_pos = -2;
101089b17223SAlexander Motin pd->pd_disk_pos = disk_pos;
101189b17223SAlexander Motin
101289b17223SAlexander Motin /* If it was placeholder -- destroy it. */
101389b17223SAlexander Motin if (olddisk->d_state == G_RAID_DISK_S_OFFLINE) {
101489b17223SAlexander Motin g_raid_destroy_disk(olddisk);
101589b17223SAlexander Motin } else {
101689b17223SAlexander Motin /* Otherwise, make it STALE_FAILED. */
101789b17223SAlexander Motin g_raid_change_disk_state(olddisk, G_RAID_DISK_S_STALE_FAILED);
101889b17223SAlexander Motin /* Update global metadata just in case. */
101989b17223SAlexander Motin memcpy(&meta->disk[disk_pos], &pd->pd_disk_meta,
102089b17223SAlexander Motin sizeof(struct intel_raid_disk));
102189b17223SAlexander Motin }
102289b17223SAlexander Motin
102389b17223SAlexander Motin /* Welcome the new disk. */
1024b99586c2SAlexander Motin if ((meta->disk[disk_pos].flags & INTEL_F_DISABLED) &&
1025b99586c2SAlexander Motin !(pd->pd_disk_meta.flags & INTEL_F_SPARE))
102626c538bcSAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_DISABLED);
1027b99586c2SAlexander Motin else if (resurrection)
1028b99586c2SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
102989b17223SAlexander Motin else if (meta->disk[disk_pos].flags & INTEL_F_FAILED)
103089b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED);
103189b17223SAlexander Motin else if (meta->disk[disk_pos].flags & INTEL_F_SPARE)
103289b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_SPARE);
103389b17223SAlexander Motin else
103489b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
103589b17223SAlexander Motin TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
103626c538bcSAlexander Motin pv = sd->sd_volume->v_md_data;
103726c538bcSAlexander Motin mvol = intel_get_volume(meta, pv->pv_volume_pos);
103889b17223SAlexander Motin mmap0 = intel_get_map(mvol, 0);
103989b17223SAlexander Motin if (mvol->migr_state)
104089b17223SAlexander Motin mmap1 = intel_get_map(mvol, 1);
104189b17223SAlexander Motin else
104289b17223SAlexander Motin mmap1 = mmap0;
104389b17223SAlexander Motin
1044865aea63SAlexander Motin migr_global = 1;
1045865aea63SAlexander Motin for (i = 0; i < mmap0->total_disks; i++) {
1046865aea63SAlexander Motin if ((mmap0->disk_idx[i] & INTEL_DI_RBLD) == 0 &&
1047865aea63SAlexander Motin (mmap1->disk_idx[i] & INTEL_DI_RBLD) != 0)
1048865aea63SAlexander Motin migr_global = 0;
1049865aea63SAlexander Motin }
1050865aea63SAlexander Motin
1051b99586c2SAlexander Motin if ((meta->disk[disk_pos].flags & INTEL_F_DISABLED) &&
1052b99586c2SAlexander Motin !(pd->pd_disk_meta.flags & INTEL_F_SPARE)) {
105326c538bcSAlexander Motin /* Disabled disk, useless. */
105426c538bcSAlexander Motin g_raid_change_subdisk_state(sd,
105526c538bcSAlexander Motin G_RAID_SUBDISK_S_NONE);
1056b99586c2SAlexander Motin } else if (resurrection) {
1057b99586c2SAlexander Motin /* Stale disk, almost same as new. */
1058b99586c2SAlexander Motin g_raid_change_subdisk_state(sd,
1059b99586c2SAlexander Motin G_RAID_SUBDISK_S_NEW);
106089b17223SAlexander Motin } else if (meta->disk[disk_pos].flags & INTEL_F_FAILED) {
106189b17223SAlexander Motin /* Failed disk, almost useless. */
106289b17223SAlexander Motin g_raid_change_subdisk_state(sd,
106389b17223SAlexander Motin G_RAID_SUBDISK_S_FAILED);
106489b17223SAlexander Motin } else if (mvol->migr_state == 0) {
106526c538bcSAlexander Motin if (mmap0->status == INTEL_S_UNINITIALIZED &&
106626c538bcSAlexander Motin (!pv->pv_cng || pv->pv_cng_master_disk != disk_pos)) {
106789b17223SAlexander Motin /* Freshly created uninitialized volume. */
106889b17223SAlexander Motin g_raid_change_subdisk_state(sd,
106989b17223SAlexander Motin G_RAID_SUBDISK_S_UNINITIALIZED);
107089b17223SAlexander Motin } else if (mmap0->disk_idx[sd->sd_pos] & INTEL_DI_RBLD) {
107189b17223SAlexander Motin /* Freshly inserted disk. */
107289b17223SAlexander Motin g_raid_change_subdisk_state(sd,
107389b17223SAlexander Motin G_RAID_SUBDISK_S_NEW);
107426c538bcSAlexander Motin } else if (mvol->dirty && (!pv->pv_cng ||
107526c538bcSAlexander Motin pv->pv_cng_master_disk != disk_pos)) {
107689b17223SAlexander Motin /* Dirty volume (unclean shutdown). */
107789b17223SAlexander Motin g_raid_change_subdisk_state(sd,
107889b17223SAlexander Motin G_RAID_SUBDISK_S_STALE);
107989b17223SAlexander Motin } else {
108089b17223SAlexander Motin /* Up to date disk. */
108189b17223SAlexander Motin g_raid_change_subdisk_state(sd,
108289b17223SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
108389b17223SAlexander Motin }
108489b17223SAlexander Motin } else if (mvol->migr_type == INTEL_MT_INIT ||
108589b17223SAlexander Motin mvol->migr_type == INTEL_MT_REBUILD) {
108689b17223SAlexander Motin if (mmap0->disk_idx[sd->sd_pos] & INTEL_DI_RBLD) {
108789b17223SAlexander Motin /* Freshly inserted disk. */
108889b17223SAlexander Motin g_raid_change_subdisk_state(sd,
108989b17223SAlexander Motin G_RAID_SUBDISK_S_NEW);
109089b17223SAlexander Motin } else if (mmap1->disk_idx[sd->sd_pos] & INTEL_DI_RBLD) {
109189b17223SAlexander Motin /* Rebuilding disk. */
109289b17223SAlexander Motin g_raid_change_subdisk_state(sd,
109389b17223SAlexander Motin G_RAID_SUBDISK_S_REBUILD);
109489b17223SAlexander Motin if (mvol->dirty) {
109589b17223SAlexander Motin sd->sd_rebuild_pos = 0;
109689b17223SAlexander Motin } else {
109789b17223SAlexander Motin sd->sd_rebuild_pos =
1098c1ad3fcfSJim Harris intel_get_vol_curr_migr_unit(mvol) *
109989b17223SAlexander Motin sd->sd_volume->v_strip_size *
110089b17223SAlexander Motin mmap0->total_domains;
110189b17223SAlexander Motin }
1102865aea63SAlexander Motin } else if (mvol->migr_type == INTEL_MT_INIT &&
1103865aea63SAlexander Motin migr_global) {
1104865aea63SAlexander Motin /* Freshly created uninitialized volume. */
1105865aea63SAlexander Motin g_raid_change_subdisk_state(sd,
1106865aea63SAlexander Motin G_RAID_SUBDISK_S_UNINITIALIZED);
110726c538bcSAlexander Motin } else if (mvol->dirty && (!pv->pv_cng ||
110826c538bcSAlexander Motin pv->pv_cng_master_disk != disk_pos)) {
110989b17223SAlexander Motin /* Dirty volume (unclean shutdown). */
111089b17223SAlexander Motin g_raid_change_subdisk_state(sd,
111189b17223SAlexander Motin G_RAID_SUBDISK_S_STALE);
111289b17223SAlexander Motin } else {
111389b17223SAlexander Motin /* Up to date disk. */
111489b17223SAlexander Motin g_raid_change_subdisk_state(sd,
111589b17223SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
111689b17223SAlexander Motin }
111789b17223SAlexander Motin } else if (mvol->migr_type == INTEL_MT_VERIFY ||
111889b17223SAlexander Motin mvol->migr_type == INTEL_MT_REPAIR) {
111989b17223SAlexander Motin if (mmap0->disk_idx[sd->sd_pos] & INTEL_DI_RBLD) {
112089b17223SAlexander Motin /* Freshly inserted disk. */
112189b17223SAlexander Motin g_raid_change_subdisk_state(sd,
112289b17223SAlexander Motin G_RAID_SUBDISK_S_NEW);
1123865aea63SAlexander Motin } else if ((mmap1->disk_idx[sd->sd_pos] & INTEL_DI_RBLD) ||
1124865aea63SAlexander Motin migr_global) {
112589b17223SAlexander Motin /* Resyncing disk. */
112689b17223SAlexander Motin g_raid_change_subdisk_state(sd,
112789b17223SAlexander Motin G_RAID_SUBDISK_S_RESYNC);
112889b17223SAlexander Motin if (mvol->dirty) {
112989b17223SAlexander Motin sd->sd_rebuild_pos = 0;
113089b17223SAlexander Motin } else {
113189b17223SAlexander Motin sd->sd_rebuild_pos =
1132c1ad3fcfSJim Harris intel_get_vol_curr_migr_unit(mvol) *
113389b17223SAlexander Motin sd->sd_volume->v_strip_size *
113489b17223SAlexander Motin mmap0->total_domains;
113589b17223SAlexander Motin }
113689b17223SAlexander Motin } else if (mvol->dirty) {
113789b17223SAlexander Motin /* Dirty volume (unclean shutdown). */
113889b17223SAlexander Motin g_raid_change_subdisk_state(sd,
113989b17223SAlexander Motin G_RAID_SUBDISK_S_STALE);
114089b17223SAlexander Motin } else {
114189b17223SAlexander Motin /* Up to date disk. */
114289b17223SAlexander Motin g_raid_change_subdisk_state(sd,
114389b17223SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
114489b17223SAlexander Motin }
11454c95a241SAlexander Motin } else if (mvol->migr_type == INTEL_MT_GEN_MIGR) {
11464c95a241SAlexander Motin if ((mmap1->disk_idx[0] & INTEL_DI_IDX) != disk_pos) {
11474c95a241SAlexander Motin /* Freshly inserted disk. */
11484c95a241SAlexander Motin g_raid_change_subdisk_state(sd,
11494c95a241SAlexander Motin G_RAID_SUBDISK_S_NEW);
11504c95a241SAlexander Motin } else {
11514c95a241SAlexander Motin /* Up to date disk. */
11524c95a241SAlexander Motin g_raid_change_subdisk_state(sd,
11534c95a241SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
11544c95a241SAlexander Motin }
115589b17223SAlexander Motin }
115689b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
115789b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
115889b17223SAlexander Motin }
115989b17223SAlexander Motin
116089b17223SAlexander Motin /* Update status of our need for spare. */
116189b17223SAlexander Motin if (mdi->mdio_started) {
116289b17223SAlexander Motin mdi->mdio_incomplete =
1163b99586c2SAlexander Motin (g_raid_ndisks(sc, G_RAID_DISK_S_ACTIVE) +
1164b99586c2SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_DISABLED) <
116589b17223SAlexander Motin meta->total_disks);
116689b17223SAlexander Motin }
116789b17223SAlexander Motin
116889b17223SAlexander Motin return (resurrection);
116989b17223SAlexander Motin }
117089b17223SAlexander Motin
117189b17223SAlexander Motin static void
g_disk_md_intel_retaste(void * arg,int pending)117289b17223SAlexander Motin g_disk_md_intel_retaste(void *arg, int pending)
117389b17223SAlexander Motin {
117489b17223SAlexander Motin
117589b17223SAlexander Motin G_RAID_DEBUG(1, "Array is not complete, trying to retaste.");
117689b17223SAlexander Motin g_retaste(&g_raid_class);
117789b17223SAlexander Motin free(arg, M_MD_INTEL);
117889b17223SAlexander Motin }
117989b17223SAlexander Motin
118089b17223SAlexander Motin static void
g_raid_md_intel_refill(struct g_raid_softc * sc)118189b17223SAlexander Motin g_raid_md_intel_refill(struct g_raid_softc *sc)
118289b17223SAlexander Motin {
118389b17223SAlexander Motin struct g_raid_md_object *md;
118489b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
118589b17223SAlexander Motin struct intel_raid_conf *meta;
118689b17223SAlexander Motin struct g_raid_disk *disk;
118789b17223SAlexander Motin struct task *task;
118889b17223SAlexander Motin int update, na;
118989b17223SAlexander Motin
119089b17223SAlexander Motin md = sc->sc_md;
119189b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
119289b17223SAlexander Motin meta = mdi->mdio_meta;
119389b17223SAlexander Motin update = 0;
119489b17223SAlexander Motin do {
119589b17223SAlexander Motin /* Make sure we miss anything. */
1196b99586c2SAlexander Motin na = g_raid_ndisks(sc, G_RAID_DISK_S_ACTIVE) +
1197b99586c2SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_DISABLED);
119889b17223SAlexander Motin if (na == meta->total_disks)
119989b17223SAlexander Motin break;
120089b17223SAlexander Motin
120189b17223SAlexander Motin G_RAID_DEBUG1(1, md->mdo_softc,
120289b17223SAlexander Motin "Array is not complete (%d of %d), "
120389b17223SAlexander Motin "trying to refill.", na, meta->total_disks);
120489b17223SAlexander Motin
120589b17223SAlexander Motin /* Try to get use some of STALE disks. */
120689b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
120789b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_STALE) {
120889b17223SAlexander Motin update += g_raid_md_intel_start_disk(disk);
1209b99586c2SAlexander Motin if (disk->d_state == G_RAID_DISK_S_ACTIVE ||
1210b99586c2SAlexander Motin disk->d_state == G_RAID_DISK_S_DISABLED)
121189b17223SAlexander Motin break;
121289b17223SAlexander Motin }
121389b17223SAlexander Motin }
121489b17223SAlexander Motin if (disk != NULL)
121589b17223SAlexander Motin continue;
121689b17223SAlexander Motin
121789b17223SAlexander Motin /* Try to get use some of SPARE disks. */
121889b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
121989b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_SPARE) {
122089b17223SAlexander Motin update += g_raid_md_intel_start_disk(disk);
122189b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_ACTIVE)
122289b17223SAlexander Motin break;
122389b17223SAlexander Motin }
122489b17223SAlexander Motin }
122589b17223SAlexander Motin } while (disk != NULL);
122689b17223SAlexander Motin
122789b17223SAlexander Motin /* Write new metadata if we changed something. */
122889b17223SAlexander Motin if (update) {
122989b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
123089b17223SAlexander Motin meta = mdi->mdio_meta;
123189b17223SAlexander Motin }
123289b17223SAlexander Motin
123389b17223SAlexander Motin /* Update status of our need for spare. */
1234b99586c2SAlexander Motin mdi->mdio_incomplete = (g_raid_ndisks(sc, G_RAID_DISK_S_ACTIVE) +
1235b99586c2SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_DISABLED) < meta->total_disks);
123689b17223SAlexander Motin
123789b17223SAlexander Motin /* Request retaste hoping to find spare. */
123889b17223SAlexander Motin if (mdi->mdio_incomplete) {
123989b17223SAlexander Motin task = malloc(sizeof(struct task),
124089b17223SAlexander Motin M_MD_INTEL, M_WAITOK | M_ZERO);
124189b17223SAlexander Motin TASK_INIT(task, 0, g_disk_md_intel_retaste, task);
124289b17223SAlexander Motin taskqueue_enqueue(taskqueue_swi, task);
124389b17223SAlexander Motin }
124489b17223SAlexander Motin }
124589b17223SAlexander Motin
124689b17223SAlexander Motin static void
g_raid_md_intel_start(struct g_raid_softc * sc)124789b17223SAlexander Motin g_raid_md_intel_start(struct g_raid_softc *sc)
124889b17223SAlexander Motin {
124989b17223SAlexander Motin struct g_raid_md_object *md;
125089b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
125126c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
125289b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
125389b17223SAlexander Motin struct intel_raid_conf *meta;
125489b17223SAlexander Motin struct intel_raid_vol *mvol;
125589b17223SAlexander Motin struct intel_raid_map *mmap;
125689b17223SAlexander Motin struct g_raid_volume *vol;
125789b17223SAlexander Motin struct g_raid_subdisk *sd;
125889b17223SAlexander Motin struct g_raid_disk *disk;
125989b17223SAlexander Motin int i, j, disk_pos;
126089b17223SAlexander Motin
126189b17223SAlexander Motin md = sc->sc_md;
126289b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
126389b17223SAlexander Motin meta = mdi->mdio_meta;
126489b17223SAlexander Motin
126589b17223SAlexander Motin /* Create volumes and subdisks. */
126689b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
126789b17223SAlexander Motin mvol = intel_get_volume(meta, i);
126889b17223SAlexander Motin mmap = intel_get_map(mvol, 0);
1269898a4b74SAlexander Motin vol = g_raid_create_volume(sc, mvol->name, mvol->tid - 1);
127026c538bcSAlexander Motin pv = malloc(sizeof(*pv), M_MD_INTEL, M_WAITOK | M_ZERO);
127126c538bcSAlexander Motin pv->pv_volume_pos = i;
127226c538bcSAlexander Motin pv->pv_cng = (mvol->state & INTEL_ST_CLONE_N_GO) != 0;
127326c538bcSAlexander Motin pv->pv_cng_man_sync = (mvol->state & INTEL_ST_CLONE_MAN_SYNC) != 0;
127426c538bcSAlexander Motin if (mvol->cng_master_disk < mmap->total_disks)
127526c538bcSAlexander Motin pv->pv_cng_master_disk = mvol->cng_master_disk;
127626c538bcSAlexander Motin vol->v_md_data = pv;
1277fc1de960SAlexander Motin vol->v_raid_level_qualifier = G_RAID_VOLUME_RLQ_NONE;
127889b17223SAlexander Motin if (mmap->type == INTEL_T_RAID0)
127989b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID0;
128089b17223SAlexander Motin else if (mmap->type == INTEL_T_RAID1 &&
128189b17223SAlexander Motin mmap->total_domains >= 2 &&
128289b17223SAlexander Motin mmap->total_domains <= mmap->total_disks) {
128389b17223SAlexander Motin /* Assume total_domains is correct. */
128489b17223SAlexander Motin if (mmap->total_domains == mmap->total_disks)
128589b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID1;
128689b17223SAlexander Motin else
128789b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E;
128889b17223SAlexander Motin } else if (mmap->type == INTEL_T_RAID1) {
128989b17223SAlexander Motin /* total_domains looks wrong. */
129089b17223SAlexander Motin if (mmap->total_disks <= 2)
129189b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID1;
129289b17223SAlexander Motin else
129389b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID1E;
1294fc1de960SAlexander Motin } else if (mmap->type == INTEL_T_RAID5) {
129589b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_RAID5;
1296fc1de960SAlexander Motin vol->v_raid_level_qualifier = G_RAID_VOLUME_RLQ_R5LA;
1297fc1de960SAlexander Motin } else
129889b17223SAlexander Motin vol->v_raid_level = G_RAID_VOLUME_RL_UNKNOWN;
129989b17223SAlexander Motin vol->v_strip_size = (u_int)mmap->strip_sectors * 512; //ZZZ
130089b17223SAlexander Motin vol->v_disks_count = mmap->total_disks;
130189b17223SAlexander Motin vol->v_mediasize = (off_t)mvol->total_sectors * 512; //ZZZ
130289b17223SAlexander Motin vol->v_sectorsize = 512; //ZZZ
130389b17223SAlexander Motin for (j = 0; j < vol->v_disks_count; j++) {
130489b17223SAlexander Motin sd = &vol->v_subdisks[j];
1305c1ad3fcfSJim Harris sd->sd_offset = intel_get_map_offset(mmap) * 512; //ZZZ
1306c1ad3fcfSJim Harris sd->sd_size = intel_get_map_disk_sectors(mmap) * 512; //ZZZ
130789b17223SAlexander Motin }
130889b17223SAlexander Motin g_raid_start_volume(vol);
130989b17223SAlexander Motin }
131089b17223SAlexander Motin
131189b17223SAlexander Motin /* Create disk placeholders to store data for later writing. */
131289b17223SAlexander Motin for (disk_pos = 0; disk_pos < meta->total_disks; disk_pos++) {
131389b17223SAlexander Motin pd = malloc(sizeof(*pd), M_MD_INTEL, M_WAITOK | M_ZERO);
131489b17223SAlexander Motin pd->pd_disk_pos = disk_pos;
131589b17223SAlexander Motin pd->pd_disk_meta = meta->disk[disk_pos];
131689b17223SAlexander Motin disk = g_raid_create_disk(sc);
131789b17223SAlexander Motin disk->d_md_data = (void *)pd;
131889b17223SAlexander Motin disk->d_state = G_RAID_DISK_S_OFFLINE;
131989b17223SAlexander Motin for (i = 0; i < meta->total_volumes; i++) {
132089b17223SAlexander Motin mvol = intel_get_volume(meta, i);
132189b17223SAlexander Motin mmap = intel_get_map(mvol, 0);
132289b17223SAlexander Motin for (j = 0; j < mmap->total_disks; j++) {
132389b17223SAlexander Motin if ((mmap->disk_idx[j] & INTEL_DI_IDX) == disk_pos)
132489b17223SAlexander Motin break;
132589b17223SAlexander Motin }
132689b17223SAlexander Motin if (j == mmap->total_disks)
132789b17223SAlexander Motin continue;
132889b17223SAlexander Motin vol = g_raid_md_intel_get_volume(sc, i);
132989b17223SAlexander Motin sd = &vol->v_subdisks[j];
133089b17223SAlexander Motin sd->sd_disk = disk;
133189b17223SAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
133289b17223SAlexander Motin }
133389b17223SAlexander Motin }
133489b17223SAlexander Motin
133589b17223SAlexander Motin /* Make all disks found till the moment take their places. */
133689b17223SAlexander Motin do {
133789b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
133889b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_NONE) {
133989b17223SAlexander Motin g_raid_md_intel_start_disk(disk);
134089b17223SAlexander Motin break;
134189b17223SAlexander Motin }
134289b17223SAlexander Motin }
134389b17223SAlexander Motin } while (disk != NULL);
134489b17223SAlexander Motin
134589b17223SAlexander Motin mdi->mdio_started = 1;
134689b17223SAlexander Motin G_RAID_DEBUG1(0, sc, "Array started.");
134789b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
134889b17223SAlexander Motin
134989b17223SAlexander Motin /* Pickup any STALE/SPARE disks to refill array if needed. */
135089b17223SAlexander Motin g_raid_md_intel_refill(sc);
135189b17223SAlexander Motin
135289b17223SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
135389b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_START,
135489b17223SAlexander Motin G_RAID_EVENT_VOLUME);
135589b17223SAlexander Motin }
135689b17223SAlexander Motin
135789b17223SAlexander Motin callout_stop(&mdi->mdio_start_co);
135889b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "root_mount_rel %p", mdi->mdio_rootmount);
135989b17223SAlexander Motin root_mount_rel(mdi->mdio_rootmount);
136089b17223SAlexander Motin mdi->mdio_rootmount = NULL;
136189b17223SAlexander Motin }
136289b17223SAlexander Motin
136389b17223SAlexander Motin static void
g_raid_md_intel_new_disk(struct g_raid_disk * disk)136489b17223SAlexander Motin g_raid_md_intel_new_disk(struct g_raid_disk *disk)
136589b17223SAlexander Motin {
136689b17223SAlexander Motin struct g_raid_softc *sc;
136789b17223SAlexander Motin struct g_raid_md_object *md;
136889b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
136989b17223SAlexander Motin struct intel_raid_conf *pdmeta;
137089b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
137189b17223SAlexander Motin
137289b17223SAlexander Motin sc = disk->d_softc;
137389b17223SAlexander Motin md = sc->sc_md;
137489b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
137589b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
137689b17223SAlexander Motin pdmeta = pd->pd_meta;
137789b17223SAlexander Motin
137889b17223SAlexander Motin if (mdi->mdio_started) {
137989b17223SAlexander Motin if (g_raid_md_intel_start_disk(disk))
138089b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
138189b17223SAlexander Motin } else {
138289b17223SAlexander Motin /* If we haven't started yet - check metadata freshness. */
138389b17223SAlexander Motin if (mdi->mdio_meta == NULL ||
138489b17223SAlexander Motin ((int32_t)(pdmeta->generation - mdi->mdio_generation)) > 0) {
138589b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "Newer disk");
138689b17223SAlexander Motin if (mdi->mdio_meta != NULL)
138789b17223SAlexander Motin free(mdi->mdio_meta, M_MD_INTEL);
138889b17223SAlexander Motin mdi->mdio_meta = intel_meta_copy(pdmeta);
138989b17223SAlexander Motin mdi->mdio_generation = mdi->mdio_meta->generation;
139089b17223SAlexander Motin mdi->mdio_disks_present = 1;
139189b17223SAlexander Motin } else if (pdmeta->generation == mdi->mdio_generation) {
139289b17223SAlexander Motin mdi->mdio_disks_present++;
139389b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "Matching disk (%d of %d up)",
139489b17223SAlexander Motin mdi->mdio_disks_present,
139589b17223SAlexander Motin mdi->mdio_meta->total_disks);
139689b17223SAlexander Motin } else {
139789b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "Older disk");
139889b17223SAlexander Motin }
139989b17223SAlexander Motin /* If we collected all needed disks - start array. */
140089b17223SAlexander Motin if (mdi->mdio_disks_present == mdi->mdio_meta->total_disks)
140189b17223SAlexander Motin g_raid_md_intel_start(sc);
140289b17223SAlexander Motin }
140389b17223SAlexander Motin }
140489b17223SAlexander Motin
140589b17223SAlexander Motin static void
g_raid_intel_go(void * arg)140689b17223SAlexander Motin g_raid_intel_go(void *arg)
140789b17223SAlexander Motin {
140889b17223SAlexander Motin struct g_raid_softc *sc;
140989b17223SAlexander Motin struct g_raid_md_object *md;
141089b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
141189b17223SAlexander Motin
141289b17223SAlexander Motin sc = arg;
141389b17223SAlexander Motin md = sc->sc_md;
141489b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
141589b17223SAlexander Motin if (!mdi->mdio_started) {
141689b17223SAlexander Motin G_RAID_DEBUG1(0, sc, "Force array start due to timeout.");
141789b17223SAlexander Motin g_raid_event_send(sc, G_RAID_NODE_E_START, 0);
141889b17223SAlexander Motin }
141989b17223SAlexander Motin }
142089b17223SAlexander Motin
142189b17223SAlexander Motin static int
g_raid_md_create_intel(struct g_raid_md_object * md,struct g_class * mp,struct g_geom ** gp)142289b17223SAlexander Motin g_raid_md_create_intel(struct g_raid_md_object *md, struct g_class *mp,
142389b17223SAlexander Motin struct g_geom **gp)
142489b17223SAlexander Motin {
142589b17223SAlexander Motin struct g_raid_softc *sc;
142689b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
142789b17223SAlexander Motin char name[16];
142889b17223SAlexander Motin
142989b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
14304c10c25eSAlexander Motin mdi->mdio_config_id = mdi->mdio_orig_config_id = arc4random();
143189b17223SAlexander Motin mdi->mdio_generation = 0;
143289b17223SAlexander Motin snprintf(name, sizeof(name), "Intel-%08x", mdi->mdio_config_id);
143389b17223SAlexander Motin sc = g_raid_create_node(mp, name, md);
143489b17223SAlexander Motin if (sc == NULL)
143589b17223SAlexander Motin return (G_RAID_MD_TASTE_FAIL);
143689b17223SAlexander Motin md->mdo_softc = sc;
143789b17223SAlexander Motin *gp = sc->sc_geom;
143889b17223SAlexander Motin return (G_RAID_MD_TASTE_NEW);
143989b17223SAlexander Motin }
144089b17223SAlexander Motin
144189b17223SAlexander Motin /*
144289b17223SAlexander Motin * Return the last N characters of the serial label. The Linux and
144389b17223SAlexander Motin * ataraid(7) code always uses the last 16 characters of the label to
144489b17223SAlexander Motin * store into the Intel meta format. Generalize this to N characters
144589b17223SAlexander Motin * since that's easy. Labels can be up to 20 characters for SATA drives
144689b17223SAlexander Motin * and up 251 characters for SAS drives. Since intel controllers don't
144789b17223SAlexander Motin * support SAS drives, just stick with the SATA limits for stack friendliness.
144889b17223SAlexander Motin */
144989b17223SAlexander Motin static int
g_raid_md_get_label(struct g_consumer * cp,char * serial,int serlen)145089b17223SAlexander Motin g_raid_md_get_label(struct g_consumer *cp, char *serial, int serlen)
145189b17223SAlexander Motin {
14522c385d51SSean Bruno char serial_buffer[DISK_IDENT_SIZE];
145389b17223SAlexander Motin int len, error;
145489b17223SAlexander Motin
145589b17223SAlexander Motin len = sizeof(serial_buffer);
145689b17223SAlexander Motin error = g_io_getattr("GEOM::ident", cp, &len, serial_buffer);
145789b17223SAlexander Motin if (error != 0)
145889b17223SAlexander Motin return (error);
145989b17223SAlexander Motin len = strlen(serial_buffer);
146089b17223SAlexander Motin if (len > serlen)
146189b17223SAlexander Motin len -= serlen;
146289b17223SAlexander Motin else
146389b17223SAlexander Motin len = 0;
146489b17223SAlexander Motin strncpy(serial, serial_buffer + len, serlen);
146589b17223SAlexander Motin return (0);
146689b17223SAlexander Motin }
146789b17223SAlexander Motin
146889b17223SAlexander Motin static int
g_raid_md_taste_intel(struct g_raid_md_object * md,struct g_class * mp,struct g_consumer * cp,struct g_geom ** gp)146989b17223SAlexander Motin g_raid_md_taste_intel(struct g_raid_md_object *md, struct g_class *mp,
147089b17223SAlexander Motin struct g_consumer *cp, struct g_geom **gp)
147189b17223SAlexander Motin {
147289b17223SAlexander Motin struct g_consumer *rcp;
147389b17223SAlexander Motin struct g_provider *pp;
147489b17223SAlexander Motin struct g_raid_md_intel_object *mdi, *mdi1;
147589b17223SAlexander Motin struct g_raid_softc *sc;
147689b17223SAlexander Motin struct g_raid_disk *disk;
147789b17223SAlexander Motin struct intel_raid_conf *meta;
147889b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
147989b17223SAlexander Motin struct g_geom *geom;
148089b17223SAlexander Motin int error, disk_pos, result, spare, len;
148189b17223SAlexander Motin char serial[INTEL_SERIAL_LEN];
148289b17223SAlexander Motin char name[16];
148389b17223SAlexander Motin uint16_t vendor;
148489b17223SAlexander Motin
148589b17223SAlexander Motin G_RAID_DEBUG(1, "Tasting Intel on %s", cp->provider->name);
148689b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
148789b17223SAlexander Motin pp = cp->provider;
148889b17223SAlexander Motin
148989b17223SAlexander Motin /* Read metadata from device. */
149089b17223SAlexander Motin meta = NULL;
149189b17223SAlexander Motin disk_pos = 0;
149289b17223SAlexander Motin g_topology_unlock();
149389b17223SAlexander Motin error = g_raid_md_get_label(cp, serial, sizeof(serial));
149489b17223SAlexander Motin if (error != 0) {
149589b17223SAlexander Motin G_RAID_DEBUG(1, "Cannot get serial number from %s (error=%d).",
149689b17223SAlexander Motin pp->name, error);
149789b17223SAlexander Motin goto fail2;
149889b17223SAlexander Motin }
14990b1b7c2cSAlexander Motin vendor = 0xffff;
15000b1b7c2cSAlexander Motin len = sizeof(vendor);
150189b17223SAlexander Motin if (pp->geom->rank == 1)
150289b17223SAlexander Motin g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor);
150389b17223SAlexander Motin meta = intel_meta_read(cp);
150489b17223SAlexander Motin g_topology_lock();
150589b17223SAlexander Motin if (meta == NULL) {
150689b17223SAlexander Motin if (g_raid_aggressive_spare) {
1507733a1f3fSAlexander Motin if (vendor != 0x8086) {
1508733a1f3fSAlexander Motin G_RAID_DEBUG(1,
1509733a1f3fSAlexander Motin "Intel vendor mismatch 0x%04x != 0x8086",
1510733a1f3fSAlexander Motin vendor);
1511733a1f3fSAlexander Motin } else {
151289b17223SAlexander Motin G_RAID_DEBUG(1,
151389b17223SAlexander Motin "No Intel metadata, forcing spare.");
151489b17223SAlexander Motin spare = 2;
151589b17223SAlexander Motin goto search;
151689b17223SAlexander Motin }
151789b17223SAlexander Motin }
151889b17223SAlexander Motin return (G_RAID_MD_TASTE_FAIL);
151989b17223SAlexander Motin }
152089b17223SAlexander Motin
152189b17223SAlexander Motin /* Check this disk position in obtained metadata. */
152289b17223SAlexander Motin disk_pos = intel_meta_find_disk(meta, serial);
152389b17223SAlexander Motin if (disk_pos < 0) {
152489b17223SAlexander Motin G_RAID_DEBUG(1, "Intel serial '%s' not found", serial);
152589b17223SAlexander Motin goto fail1;
152689b17223SAlexander Motin }
1527c1ad3fcfSJim Harris if (intel_get_disk_sectors(&meta->disk[disk_pos]) !=
152889b17223SAlexander Motin (pp->mediasize / pp->sectorsize)) {
1529733a1f3fSAlexander Motin G_RAID_DEBUG(1, "Intel size mismatch %ju != %ju",
1530c1ad3fcfSJim Harris intel_get_disk_sectors(&meta->disk[disk_pos]),
1531733a1f3fSAlexander Motin (off_t)(pp->mediasize / pp->sectorsize));
153289b17223SAlexander Motin goto fail1;
153389b17223SAlexander Motin }
153489b17223SAlexander Motin
153589b17223SAlexander Motin G_RAID_DEBUG(1, "Intel disk position %d", disk_pos);
153689b17223SAlexander Motin spare = meta->disk[disk_pos].flags & INTEL_F_SPARE;
153789b17223SAlexander Motin
153889b17223SAlexander Motin search:
153989b17223SAlexander Motin /* Search for matching node. */
154089b17223SAlexander Motin sc = NULL;
154189b17223SAlexander Motin mdi1 = NULL;
154289b17223SAlexander Motin LIST_FOREACH(geom, &mp->geom, geom) {
154389b17223SAlexander Motin sc = geom->softc;
154489b17223SAlexander Motin if (sc == NULL)
154589b17223SAlexander Motin continue;
154689b17223SAlexander Motin if (sc->sc_stopping != 0)
154789b17223SAlexander Motin continue;
154889b17223SAlexander Motin if (sc->sc_md->mdo_class != md->mdo_class)
154989b17223SAlexander Motin continue;
155089b17223SAlexander Motin mdi1 = (struct g_raid_md_intel_object *)sc->sc_md;
155189b17223SAlexander Motin if (spare) {
155289b17223SAlexander Motin if (mdi1->mdio_incomplete)
155389b17223SAlexander Motin break;
155489b17223SAlexander Motin } else {
155589b17223SAlexander Motin if (mdi1->mdio_config_id == meta->config_id)
155689b17223SAlexander Motin break;
155789b17223SAlexander Motin }
155889b17223SAlexander Motin }
155989b17223SAlexander Motin
156089b17223SAlexander Motin /* Found matching node. */
156189b17223SAlexander Motin if (geom != NULL) {
156289b17223SAlexander Motin G_RAID_DEBUG(1, "Found matching array %s", sc->sc_name);
156389b17223SAlexander Motin result = G_RAID_MD_TASTE_EXISTING;
156489b17223SAlexander Motin
156589b17223SAlexander Motin } else if (spare) { /* Not found needy node -- left for later. */
156689b17223SAlexander Motin G_RAID_DEBUG(1, "Spare is not needed at this time");
156789b17223SAlexander Motin goto fail1;
156889b17223SAlexander Motin
156989b17223SAlexander Motin } else { /* Not found matching node -- create one. */
157089b17223SAlexander Motin result = G_RAID_MD_TASTE_NEW;
157189b17223SAlexander Motin mdi->mdio_config_id = meta->config_id;
15724c10c25eSAlexander Motin mdi->mdio_orig_config_id = meta->orig_config_id;
157389b17223SAlexander Motin snprintf(name, sizeof(name), "Intel-%08x", meta->config_id);
157489b17223SAlexander Motin sc = g_raid_create_node(mp, name, md);
157589b17223SAlexander Motin md->mdo_softc = sc;
157689b17223SAlexander Motin geom = sc->sc_geom;
157789b17223SAlexander Motin callout_init(&mdi->mdio_start_co, 1);
157889b17223SAlexander Motin callout_reset(&mdi->mdio_start_co, g_raid_start_timeout * hz,
157989b17223SAlexander Motin g_raid_intel_go, sc);
158089b17223SAlexander Motin mdi->mdio_rootmount = root_mount_hold("GRAID-Intel");
158189b17223SAlexander Motin G_RAID_DEBUG1(1, sc, "root_mount_hold %p", mdi->mdio_rootmount);
158289b17223SAlexander Motin }
158389b17223SAlexander Motin
1584dea1e226SAlexander Motin /* There is no return after this point, so we close passed consumer. */
1585dea1e226SAlexander Motin g_access(cp, -1, 0, 0);
1586dea1e226SAlexander Motin
158789b17223SAlexander Motin rcp = g_new_consumer(geom);
158840ea77a0SAlexander Motin rcp->flags |= G_CF_DIRECT_RECEIVE;
158989b17223SAlexander Motin g_attach(rcp, pp);
159089b17223SAlexander Motin if (g_access(rcp, 1, 1, 1) != 0)
159189b17223SAlexander Motin ; //goto fail1;
159289b17223SAlexander Motin
159389b17223SAlexander Motin g_topology_unlock();
159489b17223SAlexander Motin sx_xlock(&sc->sc_lock);
159589b17223SAlexander Motin
159689b17223SAlexander Motin pd = malloc(sizeof(*pd), M_MD_INTEL, M_WAITOK | M_ZERO);
159789b17223SAlexander Motin pd->pd_meta = meta;
159889b17223SAlexander Motin pd->pd_disk_pos = -1;
159989b17223SAlexander Motin if (spare == 2) {
160089b17223SAlexander Motin memcpy(&pd->pd_disk_meta.serial[0], serial, INTEL_SERIAL_LEN);
1601c1ad3fcfSJim Harris intel_set_disk_sectors(&pd->pd_disk_meta,
1602c1ad3fcfSJim Harris pp->mediasize / pp->sectorsize);
160389b17223SAlexander Motin pd->pd_disk_meta.id = 0;
160489b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_SPARE;
160589b17223SAlexander Motin } else {
160689b17223SAlexander Motin pd->pd_disk_meta = meta->disk[disk_pos];
160789b17223SAlexander Motin }
160889b17223SAlexander Motin disk = g_raid_create_disk(sc);
160989b17223SAlexander Motin disk->d_md_data = (void *)pd;
161089b17223SAlexander Motin disk->d_consumer = rcp;
161189b17223SAlexander Motin rcp->private = disk;
161289b17223SAlexander Motin
1613609a7474SAlexander Motin g_raid_get_disk_info(disk);
161489b17223SAlexander Motin
161589b17223SAlexander Motin g_raid_md_intel_new_disk(disk);
161689b17223SAlexander Motin
161789b17223SAlexander Motin sx_xunlock(&sc->sc_lock);
161889b17223SAlexander Motin g_topology_lock();
161989b17223SAlexander Motin *gp = geom;
162089b17223SAlexander Motin return (result);
162189b17223SAlexander Motin fail2:
162289b17223SAlexander Motin g_topology_lock();
162389b17223SAlexander Motin fail1:
162489b17223SAlexander Motin free(meta, M_MD_INTEL);
162589b17223SAlexander Motin return (G_RAID_MD_TASTE_FAIL);
162689b17223SAlexander Motin }
162789b17223SAlexander Motin
162889b17223SAlexander Motin static int
g_raid_md_event_intel(struct g_raid_md_object * md,struct g_raid_disk * disk,u_int event)162989b17223SAlexander Motin g_raid_md_event_intel(struct g_raid_md_object *md,
163089b17223SAlexander Motin struct g_raid_disk *disk, u_int event)
163189b17223SAlexander Motin {
163289b17223SAlexander Motin struct g_raid_softc *sc;
163389b17223SAlexander Motin struct g_raid_subdisk *sd;
163489b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
163589b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
163689b17223SAlexander Motin
163789b17223SAlexander Motin sc = md->mdo_softc;
163889b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
163989b17223SAlexander Motin if (disk == NULL) {
164089b17223SAlexander Motin switch (event) {
164189b17223SAlexander Motin case G_RAID_NODE_E_START:
164289b17223SAlexander Motin if (!mdi->mdio_started)
164389b17223SAlexander Motin g_raid_md_intel_start(sc);
164489b17223SAlexander Motin return (0);
164589b17223SAlexander Motin }
164689b17223SAlexander Motin return (-1);
164789b17223SAlexander Motin }
164889b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
164989b17223SAlexander Motin switch (event) {
165089b17223SAlexander Motin case G_RAID_DISK_E_DISCONNECTED:
165189b17223SAlexander Motin /* If disk was assigned, just update statuses. */
165289b17223SAlexander Motin if (pd->pd_disk_pos >= 0) {
165389b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_OFFLINE);
165489b17223SAlexander Motin if (disk->d_consumer) {
165589b17223SAlexander Motin g_raid_kill_consumer(sc, disk->d_consumer);
165689b17223SAlexander Motin disk->d_consumer = NULL;
165789b17223SAlexander Motin }
165889b17223SAlexander Motin TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
165989b17223SAlexander Motin g_raid_change_subdisk_state(sd,
166089b17223SAlexander Motin G_RAID_SUBDISK_S_NONE);
166189b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_DISCONNECTED,
166289b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
166389b17223SAlexander Motin }
166489b17223SAlexander Motin } else {
166589b17223SAlexander Motin /* Otherwise -- delete. */
166689b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE);
166789b17223SAlexander Motin g_raid_destroy_disk(disk);
166889b17223SAlexander Motin }
166989b17223SAlexander Motin
167089b17223SAlexander Motin /* Write updated metadata to all disks. */
167189b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
167289b17223SAlexander Motin
167389b17223SAlexander Motin /* Check if anything left except placeholders. */
167489b17223SAlexander Motin if (g_raid_ndisks(sc, -1) ==
167589b17223SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_OFFLINE))
167689b17223SAlexander Motin g_raid_destroy_node(sc, 0);
167789b17223SAlexander Motin else
167889b17223SAlexander Motin g_raid_md_intel_refill(sc);
167989b17223SAlexander Motin return (0);
168089b17223SAlexander Motin }
168189b17223SAlexander Motin return (-2);
168289b17223SAlexander Motin }
168389b17223SAlexander Motin
168489b17223SAlexander Motin static int
g_raid_md_ctl_intel(struct g_raid_md_object * md,struct gctl_req * req)168589b17223SAlexander Motin g_raid_md_ctl_intel(struct g_raid_md_object *md,
168689b17223SAlexander Motin struct gctl_req *req)
168789b17223SAlexander Motin {
168889b17223SAlexander Motin struct g_raid_softc *sc;
168989b17223SAlexander Motin struct g_raid_volume *vol, *vol1;
169089b17223SAlexander Motin struct g_raid_subdisk *sd;
169189b17223SAlexander Motin struct g_raid_disk *disk;
169289b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
169326c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
169489b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
169589b17223SAlexander Motin struct g_consumer *cp;
169689b17223SAlexander Motin struct g_provider *pp;
169789b17223SAlexander Motin char arg[16], serial[INTEL_SERIAL_LEN];
16986871a543SAlexander Motin const char *nodename, *verb, *volname, *levelname, *diskname;
169989b17223SAlexander Motin char *tmp;
170089b17223SAlexander Motin int *nargs, *force;
1701c1ad3fcfSJim Harris off_t off, size, sectorsize, strip, disk_sectors;
170289b17223SAlexander Motin intmax_t *sizearg, *striparg;
170389b17223SAlexander Motin int numdisks, i, len, level, qual, update;
170489b17223SAlexander Motin int error;
170589b17223SAlexander Motin
170689b17223SAlexander Motin sc = md->mdo_softc;
170789b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
170889b17223SAlexander Motin verb = gctl_get_param(req, "verb", NULL);
170989b17223SAlexander Motin nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
171089b17223SAlexander Motin error = 0;
171189b17223SAlexander Motin if (strcmp(verb, "label") == 0) {
171289b17223SAlexander Motin if (*nargs < 4) {
171389b17223SAlexander Motin gctl_error(req, "Invalid number of arguments.");
171489b17223SAlexander Motin return (-1);
171589b17223SAlexander Motin }
171689b17223SAlexander Motin volname = gctl_get_asciiparam(req, "arg1");
171789b17223SAlexander Motin if (volname == NULL) {
171889b17223SAlexander Motin gctl_error(req, "No volume name.");
171989b17223SAlexander Motin return (-2);
172089b17223SAlexander Motin }
172189b17223SAlexander Motin levelname = gctl_get_asciiparam(req, "arg2");
172289b17223SAlexander Motin if (levelname == NULL) {
172389b17223SAlexander Motin gctl_error(req, "No RAID level.");
172489b17223SAlexander Motin return (-3);
172589b17223SAlexander Motin }
1726fc1de960SAlexander Motin if (strcasecmp(levelname, "RAID5") == 0)
17277b2a8d78SAlexander Motin levelname = "RAID5-LA";
172889b17223SAlexander Motin if (g_raid_volume_str2level(levelname, &level, &qual)) {
172989b17223SAlexander Motin gctl_error(req, "Unknown RAID level '%s'.", levelname);
173089b17223SAlexander Motin return (-4);
173189b17223SAlexander Motin }
173289b17223SAlexander Motin numdisks = *nargs - 3;
173389b17223SAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
173489b17223SAlexander Motin if (!g_raid_md_intel_supported(level, qual, numdisks,
173589b17223SAlexander Motin force ? *force : 0)) {
173689b17223SAlexander Motin gctl_error(req, "Unsupported RAID level "
173789b17223SAlexander Motin "(0x%02x/0x%02x), or number of disks (%d).",
173889b17223SAlexander Motin level, qual, numdisks);
173989b17223SAlexander Motin return (-5);
174089b17223SAlexander Motin }
174189b17223SAlexander Motin
174289b17223SAlexander Motin /* Search for disks, connect them and probe. */
174389b17223SAlexander Motin size = 0x7fffffffffffffffllu;
174489b17223SAlexander Motin sectorsize = 0;
174589b17223SAlexander Motin for (i = 0; i < numdisks; i++) {
174689b17223SAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i + 3);
174789b17223SAlexander Motin diskname = gctl_get_asciiparam(req, arg);
174889b17223SAlexander Motin if (diskname == NULL) {
174989b17223SAlexander Motin gctl_error(req, "No disk name (%s).", arg);
175089b17223SAlexander Motin error = -6;
175189b17223SAlexander Motin break;
175289b17223SAlexander Motin }
175389b17223SAlexander Motin if (strcmp(diskname, "NONE") == 0) {
175489b17223SAlexander Motin cp = NULL;
175589b17223SAlexander Motin pp = NULL;
175689b17223SAlexander Motin } else {
175789b17223SAlexander Motin g_topology_lock();
175889b17223SAlexander Motin cp = g_raid_open_consumer(sc, diskname);
175989b17223SAlexander Motin if (cp == NULL) {
176089b17223SAlexander Motin gctl_error(req, "Can't open disk '%s'.",
176189b17223SAlexander Motin diskname);
176289b17223SAlexander Motin g_topology_unlock();
176314e2cd0aSAlexander Motin error = -7;
176489b17223SAlexander Motin break;
176589b17223SAlexander Motin }
176689b17223SAlexander Motin pp = cp->provider;
176789b17223SAlexander Motin }
176889b17223SAlexander Motin pd = malloc(sizeof(*pd), M_MD_INTEL, M_WAITOK | M_ZERO);
176989b17223SAlexander Motin pd->pd_disk_pos = i;
177089b17223SAlexander Motin disk = g_raid_create_disk(sc);
177189b17223SAlexander Motin disk->d_md_data = (void *)pd;
177289b17223SAlexander Motin disk->d_consumer = cp;
177389b17223SAlexander Motin if (cp == NULL) {
177489b17223SAlexander Motin strcpy(&pd->pd_disk_meta.serial[0], "NONE");
177589b17223SAlexander Motin pd->pd_disk_meta.id = 0xffffffff;
177689b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_ASSIGNED;
177789b17223SAlexander Motin continue;
177889b17223SAlexander Motin }
177989b17223SAlexander Motin cp->private = disk;
178089b17223SAlexander Motin g_topology_unlock();
178189b17223SAlexander Motin
178289b17223SAlexander Motin error = g_raid_md_get_label(cp,
178389b17223SAlexander Motin &pd->pd_disk_meta.serial[0], INTEL_SERIAL_LEN);
178489b17223SAlexander Motin if (error != 0) {
178589b17223SAlexander Motin gctl_error(req,
178689b17223SAlexander Motin "Can't get serial for provider '%s'.",
178789b17223SAlexander Motin diskname);
178889b17223SAlexander Motin error = -8;
178989b17223SAlexander Motin break;
179089b17223SAlexander Motin }
179189b17223SAlexander Motin
1792609a7474SAlexander Motin g_raid_get_disk_info(disk);
179389b17223SAlexander Motin
1794c1ad3fcfSJim Harris intel_set_disk_sectors(&pd->pd_disk_meta,
1795c1ad3fcfSJim Harris pp->mediasize / pp->sectorsize);
179689b17223SAlexander Motin if (size > pp->mediasize)
179789b17223SAlexander Motin size = pp->mediasize;
179889b17223SAlexander Motin if (sectorsize < pp->sectorsize)
179989b17223SAlexander Motin sectorsize = pp->sectorsize;
180089b17223SAlexander Motin pd->pd_disk_meta.id = 0;
180189b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_ASSIGNED | INTEL_F_ONLINE;
180289b17223SAlexander Motin }
180389b17223SAlexander Motin if (error != 0)
180489b17223SAlexander Motin return (error);
180589b17223SAlexander Motin
180614e2cd0aSAlexander Motin if (sectorsize <= 0) {
180714e2cd0aSAlexander Motin gctl_error(req, "Can't get sector size.");
180814e2cd0aSAlexander Motin return (-8);
180914e2cd0aSAlexander Motin }
181014e2cd0aSAlexander Motin
181189b17223SAlexander Motin /* Reserve some space for metadata. */
181289b17223SAlexander Motin size -= ((4096 + sectorsize - 1) / sectorsize) * sectorsize;
181389b17223SAlexander Motin
181489b17223SAlexander Motin /* Handle size argument. */
181589b17223SAlexander Motin len = sizeof(*sizearg);
181689b17223SAlexander Motin sizearg = gctl_get_param(req, "size", &len);
181789b17223SAlexander Motin if (sizearg != NULL && len == sizeof(*sizearg) &&
181889b17223SAlexander Motin *sizearg > 0) {
181989b17223SAlexander Motin if (*sizearg > size) {
182089b17223SAlexander Motin gctl_error(req, "Size too big %lld > %lld.",
182189b17223SAlexander Motin (long long)*sizearg, (long long)size);
182289b17223SAlexander Motin return (-9);
182389b17223SAlexander Motin }
182489b17223SAlexander Motin size = *sizearg;
182589b17223SAlexander Motin }
182689b17223SAlexander Motin
182789b17223SAlexander Motin /* Handle strip argument. */
182889b17223SAlexander Motin strip = 131072;
182989b17223SAlexander Motin len = sizeof(*striparg);
183089b17223SAlexander Motin striparg = gctl_get_param(req, "strip", &len);
183189b17223SAlexander Motin if (striparg != NULL && len == sizeof(*striparg) &&
183289b17223SAlexander Motin *striparg > 0) {
183389b17223SAlexander Motin if (*striparg < sectorsize) {
183489b17223SAlexander Motin gctl_error(req, "Strip size too small.");
183589b17223SAlexander Motin return (-10);
183689b17223SAlexander Motin }
183789b17223SAlexander Motin if (*striparg % sectorsize != 0) {
183889b17223SAlexander Motin gctl_error(req, "Incorrect strip size.");
183989b17223SAlexander Motin return (-11);
184089b17223SAlexander Motin }
184189b17223SAlexander Motin if (strip > 65535 * sectorsize) {
184289b17223SAlexander Motin gctl_error(req, "Strip size too big.");
184389b17223SAlexander Motin return (-12);
184489b17223SAlexander Motin }
184589b17223SAlexander Motin strip = *striparg;
184689b17223SAlexander Motin }
184789b17223SAlexander Motin
184889b17223SAlexander Motin /* Round size down to strip or sector. */
184989b17223SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID1)
185089b17223SAlexander Motin size -= (size % sectorsize);
185189b17223SAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID1E &&
185289b17223SAlexander Motin (numdisks & 1) != 0)
185389b17223SAlexander Motin size -= (size % (2 * strip));
185489b17223SAlexander Motin else
185589b17223SAlexander Motin size -= (size % strip);
185689b17223SAlexander Motin if (size <= 0) {
185789b17223SAlexander Motin gctl_error(req, "Size too small.");
185889b17223SAlexander Motin return (-13);
185989b17223SAlexander Motin }
186089b17223SAlexander Motin
186189b17223SAlexander Motin /* We have all we need, create things: volume, ... */
186289b17223SAlexander Motin mdi->mdio_started = 1;
186389b17223SAlexander Motin vol = g_raid_create_volume(sc, volname, -1);
186426c538bcSAlexander Motin pv = malloc(sizeof(*pv), M_MD_INTEL, M_WAITOK | M_ZERO);
186526c538bcSAlexander Motin pv->pv_volume_pos = 0;
186626c538bcSAlexander Motin vol->v_md_data = pv;
186789b17223SAlexander Motin vol->v_raid_level = level;
1868fc1de960SAlexander Motin vol->v_raid_level_qualifier = qual;
186989b17223SAlexander Motin vol->v_strip_size = strip;
187089b17223SAlexander Motin vol->v_disks_count = numdisks;
187189b17223SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID0)
187289b17223SAlexander Motin vol->v_mediasize = size * numdisks;
187389b17223SAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID1)
187489b17223SAlexander Motin vol->v_mediasize = size;
187589b17223SAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID5)
187689b17223SAlexander Motin vol->v_mediasize = size * (numdisks - 1);
187789b17223SAlexander Motin else { /* RAID1E */
187889b17223SAlexander Motin vol->v_mediasize = ((size * numdisks) / strip / 2) *
187989b17223SAlexander Motin strip;
188089b17223SAlexander Motin }
188189b17223SAlexander Motin vol->v_sectorsize = sectorsize;
188289b17223SAlexander Motin g_raid_start_volume(vol);
188389b17223SAlexander Motin
188489b17223SAlexander Motin /* , and subdisks. */
188589b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
188689b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
188789b17223SAlexander Motin sd = &vol->v_subdisks[pd->pd_disk_pos];
188889b17223SAlexander Motin sd->sd_disk = disk;
188989b17223SAlexander Motin sd->sd_offset = 0;
189089b17223SAlexander Motin sd->sd_size = size;
189189b17223SAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
189289b17223SAlexander Motin if (sd->sd_disk->d_consumer != NULL) {
189389b17223SAlexander Motin g_raid_change_disk_state(disk,
189489b17223SAlexander Motin G_RAID_DISK_S_ACTIVE);
1895fc1de960SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID5)
1896fc1de960SAlexander Motin g_raid_change_subdisk_state(sd,
1897fc1de960SAlexander Motin G_RAID_SUBDISK_S_UNINITIALIZED);
1898fc1de960SAlexander Motin else
189989b17223SAlexander Motin g_raid_change_subdisk_state(sd,
190089b17223SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
190189b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
190289b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
190389b17223SAlexander Motin } else {
190489b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_OFFLINE);
190589b17223SAlexander Motin }
190689b17223SAlexander Motin }
190789b17223SAlexander Motin
190889b17223SAlexander Motin /* Write metadata based on created entities. */
190989b17223SAlexander Motin G_RAID_DEBUG1(0, sc, "Array started.");
191089b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
191189b17223SAlexander Motin
191289b17223SAlexander Motin /* Pickup any STALE/SPARE disks to refill array if needed. */
191389b17223SAlexander Motin g_raid_md_intel_refill(sc);
191489b17223SAlexander Motin
191589b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_START,
191689b17223SAlexander Motin G_RAID_EVENT_VOLUME);
191789b17223SAlexander Motin return (0);
191889b17223SAlexander Motin }
191989b17223SAlexander Motin if (strcmp(verb, "add") == 0) {
192089b17223SAlexander Motin if (*nargs != 3) {
192189b17223SAlexander Motin gctl_error(req, "Invalid number of arguments.");
192289b17223SAlexander Motin return (-1);
192389b17223SAlexander Motin }
192489b17223SAlexander Motin volname = gctl_get_asciiparam(req, "arg1");
192589b17223SAlexander Motin if (volname == NULL) {
192689b17223SAlexander Motin gctl_error(req, "No volume name.");
192789b17223SAlexander Motin return (-2);
192889b17223SAlexander Motin }
192989b17223SAlexander Motin levelname = gctl_get_asciiparam(req, "arg2");
193089b17223SAlexander Motin if (levelname == NULL) {
193189b17223SAlexander Motin gctl_error(req, "No RAID level.");
193289b17223SAlexander Motin return (-3);
193389b17223SAlexander Motin }
1934fc1de960SAlexander Motin if (strcasecmp(levelname, "RAID5") == 0)
19357b2a8d78SAlexander Motin levelname = "RAID5-LA";
193689b17223SAlexander Motin if (g_raid_volume_str2level(levelname, &level, &qual)) {
193789b17223SAlexander Motin gctl_error(req, "Unknown RAID level '%s'.", levelname);
193889b17223SAlexander Motin return (-4);
193989b17223SAlexander Motin }
194089b17223SAlexander Motin
194189b17223SAlexander Motin /* Look for existing volumes. */
194289b17223SAlexander Motin i = 0;
194389b17223SAlexander Motin vol1 = NULL;
194489b17223SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
194589b17223SAlexander Motin vol1 = vol;
194689b17223SAlexander Motin i++;
194789b17223SAlexander Motin }
194889b17223SAlexander Motin if (i > 1) {
194989b17223SAlexander Motin gctl_error(req, "Maximum two volumes supported.");
195089b17223SAlexander Motin return (-6);
195189b17223SAlexander Motin }
195289b17223SAlexander Motin if (vol1 == NULL) {
195389b17223SAlexander Motin gctl_error(req, "At least one volume must exist.");
195489b17223SAlexander Motin return (-7);
195589b17223SAlexander Motin }
195689b17223SAlexander Motin
195789b17223SAlexander Motin numdisks = vol1->v_disks_count;
195889b17223SAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
195989b17223SAlexander Motin if (!g_raid_md_intel_supported(level, qual, numdisks,
196089b17223SAlexander Motin force ? *force : 0)) {
196189b17223SAlexander Motin gctl_error(req, "Unsupported RAID level "
196289b17223SAlexander Motin "(0x%02x/0x%02x), or number of disks (%d).",
196389b17223SAlexander Motin level, qual, numdisks);
196489b17223SAlexander Motin return (-5);
196589b17223SAlexander Motin }
196689b17223SAlexander Motin
196789b17223SAlexander Motin /* Collect info about present disks. */
196889b17223SAlexander Motin size = 0x7fffffffffffffffllu;
196989b17223SAlexander Motin sectorsize = 512;
197089b17223SAlexander Motin for (i = 0; i < numdisks; i++) {
197189b17223SAlexander Motin disk = vol1->v_subdisks[i].sd_disk;
197289b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)
197389b17223SAlexander Motin disk->d_md_data;
1974c1ad3fcfSJim Harris disk_sectors =
1975c1ad3fcfSJim Harris intel_get_disk_sectors(&pd->pd_disk_meta);
1976c1ad3fcfSJim Harris
1977c1ad3fcfSJim Harris if (disk_sectors * 512 < size)
1978c1ad3fcfSJim Harris size = disk_sectors * 512;
197989b17223SAlexander Motin if (disk->d_consumer != NULL &&
198089b17223SAlexander Motin disk->d_consumer->provider != NULL &&
198189b17223SAlexander Motin disk->d_consumer->provider->sectorsize >
198289b17223SAlexander Motin sectorsize) {
198389b17223SAlexander Motin sectorsize =
198489b17223SAlexander Motin disk->d_consumer->provider->sectorsize;
198589b17223SAlexander Motin }
198689b17223SAlexander Motin }
198789b17223SAlexander Motin
198889b17223SAlexander Motin /* Reserve some space for metadata. */
198989b17223SAlexander Motin size -= ((4096 + sectorsize - 1) / sectorsize) * sectorsize;
199089b17223SAlexander Motin
199189b17223SAlexander Motin /* Decide insert before or after. */
199289b17223SAlexander Motin sd = &vol1->v_subdisks[0];
199389b17223SAlexander Motin if (sd->sd_offset >
199489b17223SAlexander Motin size - (sd->sd_offset + sd->sd_size)) {
199589b17223SAlexander Motin off = 0;
199689b17223SAlexander Motin size = sd->sd_offset;
199789b17223SAlexander Motin } else {
199889b17223SAlexander Motin off = sd->sd_offset + sd->sd_size;
199989b17223SAlexander Motin size = size - (sd->sd_offset + sd->sd_size);
200089b17223SAlexander Motin }
200189b17223SAlexander Motin
200289b17223SAlexander Motin /* Handle strip argument. */
200389b17223SAlexander Motin strip = 131072;
200489b17223SAlexander Motin len = sizeof(*striparg);
200589b17223SAlexander Motin striparg = gctl_get_param(req, "strip", &len);
200689b17223SAlexander Motin if (striparg != NULL && len == sizeof(*striparg) &&
200789b17223SAlexander Motin *striparg > 0) {
200889b17223SAlexander Motin if (*striparg < sectorsize) {
200989b17223SAlexander Motin gctl_error(req, "Strip size too small.");
201089b17223SAlexander Motin return (-10);
201189b17223SAlexander Motin }
201289b17223SAlexander Motin if (*striparg % sectorsize != 0) {
201389b17223SAlexander Motin gctl_error(req, "Incorrect strip size.");
201489b17223SAlexander Motin return (-11);
201589b17223SAlexander Motin }
201689b17223SAlexander Motin if (strip > 65535 * sectorsize) {
201789b17223SAlexander Motin gctl_error(req, "Strip size too big.");
201889b17223SAlexander Motin return (-12);
201989b17223SAlexander Motin }
202089b17223SAlexander Motin strip = *striparg;
202189b17223SAlexander Motin }
202289b17223SAlexander Motin
202389b17223SAlexander Motin /* Round offset up to strip. */
202489b17223SAlexander Motin if (off % strip != 0) {
202589b17223SAlexander Motin size -= strip - off % strip;
202689b17223SAlexander Motin off += strip - off % strip;
202789b17223SAlexander Motin }
202889b17223SAlexander Motin
202989b17223SAlexander Motin /* Handle size argument. */
203089b17223SAlexander Motin len = sizeof(*sizearg);
203189b17223SAlexander Motin sizearg = gctl_get_param(req, "size", &len);
203289b17223SAlexander Motin if (sizearg != NULL && len == sizeof(*sizearg) &&
203389b17223SAlexander Motin *sizearg > 0) {
203489b17223SAlexander Motin if (*sizearg > size) {
203589b17223SAlexander Motin gctl_error(req, "Size too big %lld > %lld.",
203689b17223SAlexander Motin (long long)*sizearg, (long long)size);
203789b17223SAlexander Motin return (-9);
203889b17223SAlexander Motin }
203989b17223SAlexander Motin size = *sizearg;
204089b17223SAlexander Motin }
204189b17223SAlexander Motin
204289b17223SAlexander Motin /* Round size down to strip or sector. */
204389b17223SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID1)
204489b17223SAlexander Motin size -= (size % sectorsize);
204589b17223SAlexander Motin else
204689b17223SAlexander Motin size -= (size % strip);
204789b17223SAlexander Motin if (size <= 0) {
204889b17223SAlexander Motin gctl_error(req, "Size too small.");
204989b17223SAlexander Motin return (-13);
205089b17223SAlexander Motin }
205189b17223SAlexander Motin if (size > 0xffffffffllu * sectorsize) {
205289b17223SAlexander Motin gctl_error(req, "Size too big.");
205389b17223SAlexander Motin return (-14);
205489b17223SAlexander Motin }
205589b17223SAlexander Motin
205689b17223SAlexander Motin /* We have all we need, create things: volume, ... */
205789b17223SAlexander Motin vol = g_raid_create_volume(sc, volname, -1);
205826c538bcSAlexander Motin pv = malloc(sizeof(*pv), M_MD_INTEL, M_WAITOK | M_ZERO);
205926c538bcSAlexander Motin pv->pv_volume_pos = i;
206026c538bcSAlexander Motin vol->v_md_data = pv;
206189b17223SAlexander Motin vol->v_raid_level = level;
2062fc1de960SAlexander Motin vol->v_raid_level_qualifier = qual;
206389b17223SAlexander Motin vol->v_strip_size = strip;
206489b17223SAlexander Motin vol->v_disks_count = numdisks;
206589b17223SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID0)
206689b17223SAlexander Motin vol->v_mediasize = size * numdisks;
206789b17223SAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID1)
206889b17223SAlexander Motin vol->v_mediasize = size;
206989b17223SAlexander Motin else if (level == G_RAID_VOLUME_RL_RAID5)
207089b17223SAlexander Motin vol->v_mediasize = size * (numdisks - 1);
207189b17223SAlexander Motin else { /* RAID1E */
207289b17223SAlexander Motin vol->v_mediasize = ((size * numdisks) / strip / 2) *
207389b17223SAlexander Motin strip;
207489b17223SAlexander Motin }
207589b17223SAlexander Motin vol->v_sectorsize = sectorsize;
207689b17223SAlexander Motin g_raid_start_volume(vol);
207789b17223SAlexander Motin
207889b17223SAlexander Motin /* , and subdisks. */
207989b17223SAlexander Motin for (i = 0; i < numdisks; i++) {
208089b17223SAlexander Motin disk = vol1->v_subdisks[i].sd_disk;
208189b17223SAlexander Motin sd = &vol->v_subdisks[i];
208289b17223SAlexander Motin sd->sd_disk = disk;
208389b17223SAlexander Motin sd->sd_offset = off;
208489b17223SAlexander Motin sd->sd_size = size;
208589b17223SAlexander Motin TAILQ_INSERT_TAIL(&disk->d_subdisks, sd, sd_next);
208689b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_ACTIVE) {
2087fc1de960SAlexander Motin if (level == G_RAID_VOLUME_RL_RAID5)
2088fc1de960SAlexander Motin g_raid_change_subdisk_state(sd,
2089fc1de960SAlexander Motin G_RAID_SUBDISK_S_UNINITIALIZED);
2090fc1de960SAlexander Motin else
209189b17223SAlexander Motin g_raid_change_subdisk_state(sd,
209289b17223SAlexander Motin G_RAID_SUBDISK_S_ACTIVE);
209389b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_NEW,
209489b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
209589b17223SAlexander Motin }
209689b17223SAlexander Motin }
209789b17223SAlexander Motin
209889b17223SAlexander Motin /* Write metadata based on created entities. */
209989b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
210089b17223SAlexander Motin
210189b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_E_START,
210289b17223SAlexander Motin G_RAID_EVENT_VOLUME);
210389b17223SAlexander Motin return (0);
210489b17223SAlexander Motin }
210589b17223SAlexander Motin if (strcmp(verb, "delete") == 0) {
21066871a543SAlexander Motin nodename = gctl_get_asciiparam(req, "arg0");
21076871a543SAlexander Motin if (nodename != NULL && strcasecmp(sc->sc_name, nodename) != 0)
21086871a543SAlexander Motin nodename = NULL;
21096871a543SAlexander Motin
211089b17223SAlexander Motin /* Full node destruction. */
21116871a543SAlexander Motin if (*nargs == 1 && nodename != NULL) {
211289b17223SAlexander Motin /* Check if some volume is still open. */
211389b17223SAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
211489b17223SAlexander Motin if (force != NULL && *force == 0 &&
211589b17223SAlexander Motin g_raid_nopens(sc) != 0) {
211689b17223SAlexander Motin gctl_error(req, "Some volume is still open.");
211789b17223SAlexander Motin return (-4);
211889b17223SAlexander Motin }
211989b17223SAlexander Motin
212089b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
212189b17223SAlexander Motin if (disk->d_consumer)
212289b17223SAlexander Motin intel_meta_erase(disk->d_consumer);
212389b17223SAlexander Motin }
212489b17223SAlexander Motin g_raid_destroy_node(sc, 0);
212589b17223SAlexander Motin return (0);
212689b17223SAlexander Motin }
212789b17223SAlexander Motin
212889b17223SAlexander Motin /* Destroy specified volume. If it was last - all node. */
21296871a543SAlexander Motin if (*nargs > 2) {
213089b17223SAlexander Motin gctl_error(req, "Invalid number of arguments.");
213189b17223SAlexander Motin return (-1);
213289b17223SAlexander Motin }
21336871a543SAlexander Motin volname = gctl_get_asciiparam(req,
21346871a543SAlexander Motin nodename != NULL ? "arg1" : "arg0");
213589b17223SAlexander Motin if (volname == NULL) {
213689b17223SAlexander Motin gctl_error(req, "No volume name.");
213789b17223SAlexander Motin return (-2);
213889b17223SAlexander Motin }
213989b17223SAlexander Motin
214089b17223SAlexander Motin /* Search for volume. */
214189b17223SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
214289b17223SAlexander Motin if (strcmp(vol->v_name, volname) == 0)
214389b17223SAlexander Motin break;
21446871a543SAlexander Motin pp = vol->v_provider;
21456871a543SAlexander Motin if (pp == NULL)
21466871a543SAlexander Motin continue;
21476871a543SAlexander Motin if (strcmp(pp->name, volname) == 0)
21486871a543SAlexander Motin break;
21496871a543SAlexander Motin if (strncmp(pp->name, "raid/", 5) == 0 &&
21506871a543SAlexander Motin strcmp(pp->name + 5, volname) == 0)
21516871a543SAlexander Motin break;
215289b17223SAlexander Motin }
215389b17223SAlexander Motin if (vol == NULL) {
215489b17223SAlexander Motin i = strtol(volname, &tmp, 10);
215589b17223SAlexander Motin if (verb != volname && tmp[0] == 0) {
215689b17223SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
215789b17223SAlexander Motin if (vol->v_global_id == i)
215889b17223SAlexander Motin break;
215989b17223SAlexander Motin }
216089b17223SAlexander Motin }
216189b17223SAlexander Motin }
216289b17223SAlexander Motin if (vol == NULL) {
216389b17223SAlexander Motin gctl_error(req, "Volume '%s' not found.", volname);
216489b17223SAlexander Motin return (-3);
216589b17223SAlexander Motin }
216689b17223SAlexander Motin
216789b17223SAlexander Motin /* Check if volume is still open. */
216889b17223SAlexander Motin force = gctl_get_paraml(req, "force", sizeof(*force));
216989b17223SAlexander Motin if (force != NULL && *force == 0 &&
217089b17223SAlexander Motin vol->v_provider_open != 0) {
217189b17223SAlexander Motin gctl_error(req, "Volume is still open.");
217289b17223SAlexander Motin return (-4);
217389b17223SAlexander Motin }
217489b17223SAlexander Motin
217589b17223SAlexander Motin /* Destroy volume and potentially node. */
217689b17223SAlexander Motin i = 0;
217789b17223SAlexander Motin TAILQ_FOREACH(vol1, &sc->sc_volumes, v_next)
217889b17223SAlexander Motin i++;
217989b17223SAlexander Motin if (i >= 2) {
218089b17223SAlexander Motin g_raid_destroy_volume(vol);
218189b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
218289b17223SAlexander Motin } else {
218389b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
218489b17223SAlexander Motin if (disk->d_consumer)
218589b17223SAlexander Motin intel_meta_erase(disk->d_consumer);
218689b17223SAlexander Motin }
218789b17223SAlexander Motin g_raid_destroy_node(sc, 0);
218889b17223SAlexander Motin }
218989b17223SAlexander Motin return (0);
219089b17223SAlexander Motin }
219189b17223SAlexander Motin if (strcmp(verb, "remove") == 0 ||
219289b17223SAlexander Motin strcmp(verb, "fail") == 0) {
219389b17223SAlexander Motin if (*nargs < 2) {
219489b17223SAlexander Motin gctl_error(req, "Invalid number of arguments.");
219589b17223SAlexander Motin return (-1);
219689b17223SAlexander Motin }
219789b17223SAlexander Motin for (i = 1; i < *nargs; i++) {
219889b17223SAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i);
219989b17223SAlexander Motin diskname = gctl_get_asciiparam(req, arg);
220089b17223SAlexander Motin if (diskname == NULL) {
220189b17223SAlexander Motin gctl_error(req, "No disk name (%s).", arg);
220289b17223SAlexander Motin error = -2;
220389b17223SAlexander Motin break;
220489b17223SAlexander Motin }
22058510f61aSXin LI if (strncmp(diskname, _PATH_DEV, 5) == 0)
220689b17223SAlexander Motin diskname += 5;
220789b17223SAlexander Motin
220889b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
220989b17223SAlexander Motin if (disk->d_consumer != NULL &&
221089b17223SAlexander Motin disk->d_consumer->provider != NULL &&
221189b17223SAlexander Motin strcmp(disk->d_consumer->provider->name,
221289b17223SAlexander Motin diskname) == 0)
221389b17223SAlexander Motin break;
221489b17223SAlexander Motin }
221589b17223SAlexander Motin if (disk == NULL) {
221689b17223SAlexander Motin gctl_error(req, "Disk '%s' not found.",
221789b17223SAlexander Motin diskname);
221889b17223SAlexander Motin error = -3;
221989b17223SAlexander Motin break;
222089b17223SAlexander Motin }
222189b17223SAlexander Motin
222289b17223SAlexander Motin if (strcmp(verb, "fail") == 0) {
222389b17223SAlexander Motin g_raid_md_fail_disk_intel(md, NULL, disk);
222489b17223SAlexander Motin continue;
222589b17223SAlexander Motin }
222689b17223SAlexander Motin
222789b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
222889b17223SAlexander Motin
222989b17223SAlexander Motin /* Erase metadata on deleting disk. */
223089b17223SAlexander Motin intel_meta_erase(disk->d_consumer);
223189b17223SAlexander Motin
223289b17223SAlexander Motin /* If disk was assigned, just update statuses. */
223389b17223SAlexander Motin if (pd->pd_disk_pos >= 0) {
223489b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_OFFLINE);
223589b17223SAlexander Motin g_raid_kill_consumer(sc, disk->d_consumer);
223689b17223SAlexander Motin disk->d_consumer = NULL;
223789b17223SAlexander Motin TAILQ_FOREACH(sd, &disk->d_subdisks, sd_next) {
223889b17223SAlexander Motin g_raid_change_subdisk_state(sd,
223989b17223SAlexander Motin G_RAID_SUBDISK_S_NONE);
224089b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_DISCONNECTED,
224189b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
224289b17223SAlexander Motin }
224389b17223SAlexander Motin } else {
224489b17223SAlexander Motin /* Otherwise -- delete. */
224589b17223SAlexander Motin g_raid_change_disk_state(disk, G_RAID_DISK_S_NONE);
224689b17223SAlexander Motin g_raid_destroy_disk(disk);
224789b17223SAlexander Motin }
224889b17223SAlexander Motin }
224989b17223SAlexander Motin
225089b17223SAlexander Motin /* Write updated metadata to remaining disks. */
225189b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
225289b17223SAlexander Motin
225389b17223SAlexander Motin /* Check if anything left except placeholders. */
225489b17223SAlexander Motin if (g_raid_ndisks(sc, -1) ==
225589b17223SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_OFFLINE))
225689b17223SAlexander Motin g_raid_destroy_node(sc, 0);
225789b17223SAlexander Motin else
225889b17223SAlexander Motin g_raid_md_intel_refill(sc);
225989b17223SAlexander Motin return (error);
226089b17223SAlexander Motin }
226189b17223SAlexander Motin if (strcmp(verb, "insert") == 0) {
226289b17223SAlexander Motin if (*nargs < 2) {
226389b17223SAlexander Motin gctl_error(req, "Invalid number of arguments.");
226489b17223SAlexander Motin return (-1);
226589b17223SAlexander Motin }
226689b17223SAlexander Motin update = 0;
226789b17223SAlexander Motin for (i = 1; i < *nargs; i++) {
226889b17223SAlexander Motin /* Get disk name. */
226989b17223SAlexander Motin snprintf(arg, sizeof(arg), "arg%d", i);
227089b17223SAlexander Motin diskname = gctl_get_asciiparam(req, arg);
227189b17223SAlexander Motin if (diskname == NULL) {
227289b17223SAlexander Motin gctl_error(req, "No disk name (%s).", arg);
227389b17223SAlexander Motin error = -3;
227489b17223SAlexander Motin break;
227589b17223SAlexander Motin }
227689b17223SAlexander Motin
227789b17223SAlexander Motin /* Try to find provider with specified name. */
227889b17223SAlexander Motin g_topology_lock();
227989b17223SAlexander Motin cp = g_raid_open_consumer(sc, diskname);
228089b17223SAlexander Motin if (cp == NULL) {
228189b17223SAlexander Motin gctl_error(req, "Can't open disk '%s'.",
228289b17223SAlexander Motin diskname);
228389b17223SAlexander Motin g_topology_unlock();
228489b17223SAlexander Motin error = -4;
228589b17223SAlexander Motin break;
228689b17223SAlexander Motin }
228789b17223SAlexander Motin pp = cp->provider;
228889b17223SAlexander Motin g_topology_unlock();
228989b17223SAlexander Motin
229089b17223SAlexander Motin /* Read disk serial. */
229189b17223SAlexander Motin error = g_raid_md_get_label(cp,
229289b17223SAlexander Motin &serial[0], INTEL_SERIAL_LEN);
229389b17223SAlexander Motin if (error != 0) {
229489b17223SAlexander Motin gctl_error(req,
229589b17223SAlexander Motin "Can't get serial for provider '%s'.",
229689b17223SAlexander Motin diskname);
229789b17223SAlexander Motin g_raid_kill_consumer(sc, cp);
229889b17223SAlexander Motin error = -7;
229989b17223SAlexander Motin break;
230089b17223SAlexander Motin }
230189b17223SAlexander Motin
230289b17223SAlexander Motin pd = malloc(sizeof(*pd), M_MD_INTEL, M_WAITOK | M_ZERO);
230389b17223SAlexander Motin pd->pd_disk_pos = -1;
230489b17223SAlexander Motin
230589b17223SAlexander Motin disk = g_raid_create_disk(sc);
230689b17223SAlexander Motin disk->d_consumer = cp;
230789b17223SAlexander Motin disk->d_md_data = (void *)pd;
230889b17223SAlexander Motin cp->private = disk;
230989b17223SAlexander Motin
2310609a7474SAlexander Motin g_raid_get_disk_info(disk);
231189b17223SAlexander Motin
231289b17223SAlexander Motin memcpy(&pd->pd_disk_meta.serial[0], &serial[0],
231389b17223SAlexander Motin INTEL_SERIAL_LEN);
2314c1ad3fcfSJim Harris intel_set_disk_sectors(&pd->pd_disk_meta,
2315c1ad3fcfSJim Harris pp->mediasize / pp->sectorsize);
231689b17223SAlexander Motin pd->pd_disk_meta.id = 0;
231789b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_SPARE;
231889b17223SAlexander Motin
231989b17223SAlexander Motin /* Welcome the "new" disk. */
232089b17223SAlexander Motin update += g_raid_md_intel_start_disk(disk);
232189b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_SPARE) {
232289b17223SAlexander Motin intel_meta_write_spare(cp, &pd->pd_disk_meta);
232389b17223SAlexander Motin g_raid_destroy_disk(disk);
232489b17223SAlexander Motin } else if (disk->d_state != G_RAID_DISK_S_ACTIVE) {
232589b17223SAlexander Motin gctl_error(req, "Disk '%s' doesn't fit.",
232689b17223SAlexander Motin diskname);
232789b17223SAlexander Motin g_raid_destroy_disk(disk);
232889b17223SAlexander Motin error = -8;
232989b17223SAlexander Motin break;
233089b17223SAlexander Motin }
233189b17223SAlexander Motin }
233289b17223SAlexander Motin
233389b17223SAlexander Motin /* Write new metadata if we changed something. */
233489b17223SAlexander Motin if (update)
233589b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, NULL);
233689b17223SAlexander Motin return (error);
233789b17223SAlexander Motin }
233889b17223SAlexander Motin return (-100);
233989b17223SAlexander Motin }
234089b17223SAlexander Motin
234189b17223SAlexander Motin static int
g_raid_md_write_intel(struct g_raid_md_object * md,struct g_raid_volume * tvol,struct g_raid_subdisk * tsd,struct g_raid_disk * tdisk)234289b17223SAlexander Motin g_raid_md_write_intel(struct g_raid_md_object *md, struct g_raid_volume *tvol,
234389b17223SAlexander Motin struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
234489b17223SAlexander Motin {
234589b17223SAlexander Motin struct g_raid_softc *sc;
234689b17223SAlexander Motin struct g_raid_volume *vol;
234789b17223SAlexander Motin struct g_raid_subdisk *sd;
234889b17223SAlexander Motin struct g_raid_disk *disk;
234989b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
235026c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
235189b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
235289b17223SAlexander Motin struct intel_raid_conf *meta;
235389b17223SAlexander Motin struct intel_raid_vol *mvol;
235489b17223SAlexander Motin struct intel_raid_map *mmap0, *mmap1;
235589b17223SAlexander Motin off_t sectorsize = 512, pos;
235689b17223SAlexander Motin const char *version, *cv;
235789b17223SAlexander Motin int vi, sdi, numdisks, len, state, stale;
235889b17223SAlexander Motin
235989b17223SAlexander Motin sc = md->mdo_softc;
236089b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
236189b17223SAlexander Motin
236289b17223SAlexander Motin if (sc->sc_stopping == G_RAID_DESTROY_HARD)
236389b17223SAlexander Motin return (0);
236489b17223SAlexander Motin
236589b17223SAlexander Motin /* Bump generation. Newly written metadata may differ from previous. */
236689b17223SAlexander Motin mdi->mdio_generation++;
236789b17223SAlexander Motin
236889b17223SAlexander Motin /* Count number of disks. */
236989b17223SAlexander Motin numdisks = 0;
237089b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
237189b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
237289b17223SAlexander Motin if (pd->pd_disk_pos < 0)
237389b17223SAlexander Motin continue;
237489b17223SAlexander Motin numdisks++;
237589b17223SAlexander Motin if (disk->d_state == G_RAID_DISK_S_ACTIVE) {
237689b17223SAlexander Motin pd->pd_disk_meta.flags =
237789b17223SAlexander Motin INTEL_F_ONLINE | INTEL_F_ASSIGNED;
237889b17223SAlexander Motin } else if (disk->d_state == G_RAID_DISK_S_FAILED) {
237926c538bcSAlexander Motin pd->pd_disk_meta.flags = INTEL_F_FAILED |
238026c538bcSAlexander Motin INTEL_F_ASSIGNED;
238126c538bcSAlexander Motin } else if (disk->d_state == G_RAID_DISK_S_DISABLED) {
238226c538bcSAlexander Motin pd->pd_disk_meta.flags = INTEL_F_FAILED |
238326c538bcSAlexander Motin INTEL_F_ASSIGNED | INTEL_F_DISABLED;
238489b17223SAlexander Motin } else {
2385b99586c2SAlexander Motin if (!(pd->pd_disk_meta.flags & INTEL_F_DISABLED))
238689b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_ASSIGNED;
238789b17223SAlexander Motin if (pd->pd_disk_meta.id != 0xffffffff) {
238889b17223SAlexander Motin pd->pd_disk_meta.id = 0xffffffff;
238989b17223SAlexander Motin len = strlen(pd->pd_disk_meta.serial);
239089b17223SAlexander Motin len = min(len, INTEL_SERIAL_LEN - 3);
239189b17223SAlexander Motin strcpy(pd->pd_disk_meta.serial + len, ":0");
239289b17223SAlexander Motin }
239389b17223SAlexander Motin }
239489b17223SAlexander Motin }
239589b17223SAlexander Motin
239689b17223SAlexander Motin /* Fill anchor and disks. */
239789b17223SAlexander Motin meta = malloc(INTEL_MAX_MD_SIZE(numdisks),
239889b17223SAlexander Motin M_MD_INTEL, M_WAITOK | M_ZERO);
239963607675SAlexander Motin memcpy(&meta->intel_id[0], INTEL_MAGIC, sizeof(INTEL_MAGIC) - 1);
240089b17223SAlexander Motin meta->config_size = INTEL_MAX_MD_SIZE(numdisks);
240189b17223SAlexander Motin meta->config_id = mdi->mdio_config_id;
24024c10c25eSAlexander Motin meta->orig_config_id = mdi->mdio_orig_config_id;
240389b17223SAlexander Motin meta->generation = mdi->mdio_generation;
240489b17223SAlexander Motin meta->attributes = INTEL_ATTR_CHECKSUM;
240589b17223SAlexander Motin meta->total_disks = numdisks;
240689b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
240789b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
240889b17223SAlexander Motin if (pd->pd_disk_pos < 0)
240989b17223SAlexander Motin continue;
241089b17223SAlexander Motin meta->disk[pd->pd_disk_pos] = pd->pd_disk_meta;
2411f9462b9bSAlexander Motin if (pd->pd_disk_meta.sectors_hi != 0)
2412f9462b9bSAlexander Motin meta->attributes |= INTEL_ATTR_2TB_DISK;
241389b17223SAlexander Motin }
241489b17223SAlexander Motin
241589b17223SAlexander Motin /* Fill volumes and maps. */
241689b17223SAlexander Motin vi = 0;
241789b17223SAlexander Motin version = INTEL_VERSION_1000;
241889b17223SAlexander Motin TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) {
241926c538bcSAlexander Motin pv = vol->v_md_data;
242089b17223SAlexander Motin if (vol->v_stopping)
242189b17223SAlexander Motin continue;
242289b17223SAlexander Motin mvol = intel_get_volume(meta, vi);
242389b17223SAlexander Motin
242489b17223SAlexander Motin /* New metadata may have different volumes order. */
242526c538bcSAlexander Motin pv->pv_volume_pos = vi;
242689b17223SAlexander Motin
242789b17223SAlexander Motin for (sdi = 0; sdi < vol->v_disks_count; sdi++) {
242889b17223SAlexander Motin sd = &vol->v_subdisks[sdi];
242989b17223SAlexander Motin if (sd->sd_disk != NULL)
243089b17223SAlexander Motin break;
243189b17223SAlexander Motin }
243289b17223SAlexander Motin if (sdi >= vol->v_disks_count)
243389b17223SAlexander Motin panic("No any filled subdisk in volume");
243489b17223SAlexander Motin if (vol->v_mediasize >= 0x20000000000llu)
243589b17223SAlexander Motin meta->attributes |= INTEL_ATTR_2TB;
243689b17223SAlexander Motin if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID0)
243789b17223SAlexander Motin meta->attributes |= INTEL_ATTR_RAID0;
243889b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1)
243989b17223SAlexander Motin meta->attributes |= INTEL_ATTR_RAID1;
244089b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID5)
244189b17223SAlexander Motin meta->attributes |= INTEL_ATTR_RAID5;
2442f9462b9bSAlexander Motin else if ((vol->v_disks_count & 1) == 0)
244389b17223SAlexander Motin meta->attributes |= INTEL_ATTR_RAID10;
2444f9462b9bSAlexander Motin else
2445f9462b9bSAlexander Motin meta->attributes |= INTEL_ATTR_RAID1E;
2446f9462b9bSAlexander Motin if (pv->pv_cng)
2447f9462b9bSAlexander Motin meta->attributes |= INTEL_ATTR_RAIDCNG;
2448f9462b9bSAlexander Motin if (vol->v_strip_size > 131072)
2449f9462b9bSAlexander Motin meta->attributes |= INTEL_ATTR_EXT_STRIP;
245089b17223SAlexander Motin
2451f9462b9bSAlexander Motin if (pv->pv_cng)
245226c538bcSAlexander Motin cv = INTEL_VERSION_1206;
245389b17223SAlexander Motin else if (vol->v_disks_count > 4)
245489b17223SAlexander Motin cv = INTEL_VERSION_1204;
245589b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID5)
245689b17223SAlexander Motin cv = INTEL_VERSION_1202;
245789b17223SAlexander Motin else if (vol->v_disks_count > 2)
245889b17223SAlexander Motin cv = INTEL_VERSION_1201;
245989b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1)
246089b17223SAlexander Motin cv = INTEL_VERSION_1100;
246189b17223SAlexander Motin else
246289b17223SAlexander Motin cv = INTEL_VERSION_1000;
246389b17223SAlexander Motin if (strcmp(cv, version) > 0)
246489b17223SAlexander Motin version = cv;
246589b17223SAlexander Motin
246689b17223SAlexander Motin strlcpy(&mvol->name[0], vol->v_name, sizeof(mvol->name));
246789b17223SAlexander Motin mvol->total_sectors = vol->v_mediasize / sectorsize;
2468f9462b9bSAlexander Motin mvol->state = (INTEL_ST_READ_COALESCING |
2469f9462b9bSAlexander Motin INTEL_ST_WRITE_COALESCING);
2470898a4b74SAlexander Motin mvol->tid = vol->v_global_id + 1;
247126c538bcSAlexander Motin if (pv->pv_cng) {
247226c538bcSAlexander Motin mvol->state |= INTEL_ST_CLONE_N_GO;
247326c538bcSAlexander Motin if (pv->pv_cng_man_sync)
247426c538bcSAlexander Motin mvol->state |= INTEL_ST_CLONE_MAN_SYNC;
247526c538bcSAlexander Motin mvol->cng_master_disk = pv->pv_cng_master_disk;
247626c538bcSAlexander Motin if (vol->v_subdisks[pv->pv_cng_master_disk].sd_state ==
247726c538bcSAlexander Motin G_RAID_SUBDISK_S_NONE)
2478eb84fc95SAlexander Motin mvol->cng_state = INTEL_CNGST_MASTER_MISSING;
247926c538bcSAlexander Motin else if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL)
2480eb84fc95SAlexander Motin mvol->cng_state = INTEL_CNGST_NEEDS_UPDATE;
2481eb84fc95SAlexander Motin else
2482eb84fc95SAlexander Motin mvol->cng_state = INTEL_CNGST_UPDATED;
248326c538bcSAlexander Motin }
248489b17223SAlexander Motin
248589b17223SAlexander Motin /* Check for any recovery in progress. */
248689b17223SAlexander Motin state = G_RAID_SUBDISK_S_ACTIVE;
248789b17223SAlexander Motin pos = 0x7fffffffffffffffllu;
248889b17223SAlexander Motin stale = 0;
248989b17223SAlexander Motin for (sdi = 0; sdi < vol->v_disks_count; sdi++) {
249089b17223SAlexander Motin sd = &vol->v_subdisks[sdi];
249189b17223SAlexander Motin if (sd->sd_state == G_RAID_SUBDISK_S_REBUILD)
249289b17223SAlexander Motin state = G_RAID_SUBDISK_S_REBUILD;
249389b17223SAlexander Motin else if (sd->sd_state == G_RAID_SUBDISK_S_RESYNC &&
249489b17223SAlexander Motin state != G_RAID_SUBDISK_S_REBUILD)
249589b17223SAlexander Motin state = G_RAID_SUBDISK_S_RESYNC;
249689b17223SAlexander Motin else if (sd->sd_state == G_RAID_SUBDISK_S_STALE)
249789b17223SAlexander Motin stale = 1;
249889b17223SAlexander Motin if ((sd->sd_state == G_RAID_SUBDISK_S_REBUILD ||
249989b17223SAlexander Motin sd->sd_state == G_RAID_SUBDISK_S_RESYNC) &&
250089b17223SAlexander Motin sd->sd_rebuild_pos < pos)
250189b17223SAlexander Motin pos = sd->sd_rebuild_pos;
250289b17223SAlexander Motin }
250389b17223SAlexander Motin if (state == G_RAID_SUBDISK_S_REBUILD) {
250489b17223SAlexander Motin mvol->migr_state = 1;
250589b17223SAlexander Motin mvol->migr_type = INTEL_MT_REBUILD;
250689b17223SAlexander Motin } else if (state == G_RAID_SUBDISK_S_RESYNC) {
250789b17223SAlexander Motin mvol->migr_state = 1;
250889b17223SAlexander Motin /* mvol->migr_type = INTEL_MT_REPAIR; */
250989b17223SAlexander Motin mvol->migr_type = INTEL_MT_VERIFY;
251089b17223SAlexander Motin mvol->state |= INTEL_ST_VERIFY_AND_FIX;
251189b17223SAlexander Motin } else
251289b17223SAlexander Motin mvol->migr_state = 0;
251389b17223SAlexander Motin mvol->dirty = (vol->v_dirty || stale);
251489b17223SAlexander Motin
251589b17223SAlexander Motin mmap0 = intel_get_map(mvol, 0);
251689b17223SAlexander Motin
251789b17223SAlexander Motin /* Write map / common part of two maps. */
2518c1ad3fcfSJim Harris intel_set_map_offset(mmap0, sd->sd_offset / sectorsize);
2519c1ad3fcfSJim Harris intel_set_map_disk_sectors(mmap0, sd->sd_size / sectorsize);
252089b17223SAlexander Motin mmap0->strip_sectors = vol->v_strip_size / sectorsize;
252189b17223SAlexander Motin if (vol->v_state == G_RAID_VOLUME_S_BROKEN)
252289b17223SAlexander Motin mmap0->status = INTEL_S_FAILURE;
252389b17223SAlexander Motin else if (vol->v_state == G_RAID_VOLUME_S_DEGRADED)
252489b17223SAlexander Motin mmap0->status = INTEL_S_DEGRADED;
2525fc1de960SAlexander Motin else if (g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_UNINITIALIZED)
2526fc1de960SAlexander Motin == g_raid_nsubdisks(vol, -1))
2527fc1de960SAlexander Motin mmap0->status = INTEL_S_UNINITIALIZED;
252889b17223SAlexander Motin else
252989b17223SAlexander Motin mmap0->status = INTEL_S_READY;
253089b17223SAlexander Motin if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID0)
253189b17223SAlexander Motin mmap0->type = INTEL_T_RAID0;
253289b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1 ||
253389b17223SAlexander Motin vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E)
253489b17223SAlexander Motin mmap0->type = INTEL_T_RAID1;
253589b17223SAlexander Motin else
253689b17223SAlexander Motin mmap0->type = INTEL_T_RAID5;
253789b17223SAlexander Motin mmap0->total_disks = vol->v_disks_count;
253889b17223SAlexander Motin if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1)
253989b17223SAlexander Motin mmap0->total_domains = vol->v_disks_count;
254089b17223SAlexander Motin else if (vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E)
254189b17223SAlexander Motin mmap0->total_domains = 2;
254289b17223SAlexander Motin else
254389b17223SAlexander Motin mmap0->total_domains = 1;
2544c1ad3fcfSJim Harris intel_set_map_stripe_count(mmap0,
2545c1ad3fcfSJim Harris sd->sd_size / vol->v_strip_size / mmap0->total_domains);
254689b17223SAlexander Motin mmap0->failed_disk_num = 0xff;
254789b17223SAlexander Motin mmap0->ddf = 1;
254889b17223SAlexander Motin
254989b17223SAlexander Motin /* If there are two maps - copy common and update. */
255089b17223SAlexander Motin if (mvol->migr_state) {
2551c1ad3fcfSJim Harris intel_set_vol_curr_migr_unit(mvol,
2552c1ad3fcfSJim Harris pos / vol->v_strip_size / mmap0->total_domains);
255389b17223SAlexander Motin mmap1 = intel_get_map(mvol, 1);
255489b17223SAlexander Motin memcpy(mmap1, mmap0, sizeof(struct intel_raid_map));
255589b17223SAlexander Motin mmap0->status = INTEL_S_READY;
255689b17223SAlexander Motin } else
255789b17223SAlexander Motin mmap1 = NULL;
255889b17223SAlexander Motin
255989b17223SAlexander Motin /* Write disk indexes and put rebuild flags. */
256089b17223SAlexander Motin for (sdi = 0; sdi < vol->v_disks_count; sdi++) {
256189b17223SAlexander Motin sd = &vol->v_subdisks[sdi];
256289b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)
256389b17223SAlexander Motin sd->sd_disk->d_md_data;
256489b17223SAlexander Motin mmap0->disk_idx[sdi] = pd->pd_disk_pos;
256589b17223SAlexander Motin if (mvol->migr_state)
256689b17223SAlexander Motin mmap1->disk_idx[sdi] = pd->pd_disk_pos;
256789b17223SAlexander Motin if (sd->sd_state == G_RAID_SUBDISK_S_REBUILD ||
256889b17223SAlexander Motin sd->sd_state == G_RAID_SUBDISK_S_RESYNC) {
256989b17223SAlexander Motin mmap1->disk_idx[sdi] |= INTEL_DI_RBLD;
257089b17223SAlexander Motin } else if (sd->sd_state != G_RAID_SUBDISK_S_ACTIVE &&
2571fc1de960SAlexander Motin sd->sd_state != G_RAID_SUBDISK_S_STALE &&
2572fc1de960SAlexander Motin sd->sd_state != G_RAID_SUBDISK_S_UNINITIALIZED) {
257389b17223SAlexander Motin mmap0->disk_idx[sdi] |= INTEL_DI_RBLD;
257489b17223SAlexander Motin if (mvol->migr_state)
257589b17223SAlexander Motin mmap1->disk_idx[sdi] |= INTEL_DI_RBLD;
257689b17223SAlexander Motin }
257789b17223SAlexander Motin if ((sd->sd_state == G_RAID_SUBDISK_S_NONE ||
25784c95a241SAlexander Motin sd->sd_state == G_RAID_SUBDISK_S_FAILED ||
25794c95a241SAlexander Motin sd->sd_state == G_RAID_SUBDISK_S_REBUILD) &&
258089b17223SAlexander Motin mmap0->failed_disk_num == 0xff) {
258189b17223SAlexander Motin mmap0->failed_disk_num = sdi;
258289b17223SAlexander Motin if (mvol->migr_state)
258389b17223SAlexander Motin mmap1->failed_disk_num = sdi;
258489b17223SAlexander Motin }
258589b17223SAlexander Motin }
258689b17223SAlexander Motin vi++;
258789b17223SAlexander Motin }
258889b17223SAlexander Motin meta->total_volumes = vi;
2589f9462b9bSAlexander Motin if (vi > 1 || meta->attributes &
2590f9462b9bSAlexander Motin (INTEL_ATTR_EXT_STRIP | INTEL_ATTR_2TB_DISK | INTEL_ATTR_2TB))
2591f9462b9bSAlexander Motin version = INTEL_VERSION_1300;
2592f9462b9bSAlexander Motin if (strcmp(version, INTEL_VERSION_1300) < 0)
259389b17223SAlexander Motin meta->attributes &= INTEL_ATTR_CHECKSUM;
259463607675SAlexander Motin memcpy(&meta->version[0], version, sizeof(INTEL_VERSION_1000) - 1);
259589b17223SAlexander Motin
259689b17223SAlexander Motin /* We are done. Print meta data and store them to disks. */
259789b17223SAlexander Motin g_raid_md_intel_print(meta);
259889b17223SAlexander Motin if (mdi->mdio_meta != NULL)
259989b17223SAlexander Motin free(mdi->mdio_meta, M_MD_INTEL);
260089b17223SAlexander Motin mdi->mdio_meta = meta;
260189b17223SAlexander Motin TAILQ_FOREACH(disk, &sc->sc_disks, d_next) {
260289b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
260389b17223SAlexander Motin if (disk->d_state != G_RAID_DISK_S_ACTIVE)
260489b17223SAlexander Motin continue;
260589b17223SAlexander Motin if (pd->pd_meta != NULL) {
260689b17223SAlexander Motin free(pd->pd_meta, M_MD_INTEL);
260789b17223SAlexander Motin pd->pd_meta = NULL;
260889b17223SAlexander Motin }
260989b17223SAlexander Motin pd->pd_meta = intel_meta_copy(meta);
261089b17223SAlexander Motin intel_meta_write(disk->d_consumer, meta);
261189b17223SAlexander Motin }
261289b17223SAlexander Motin return (0);
261389b17223SAlexander Motin }
261489b17223SAlexander Motin
261589b17223SAlexander Motin static int
g_raid_md_fail_disk_intel(struct g_raid_md_object * md,struct g_raid_subdisk * tsd,struct g_raid_disk * tdisk)261689b17223SAlexander Motin g_raid_md_fail_disk_intel(struct g_raid_md_object *md,
261789b17223SAlexander Motin struct g_raid_subdisk *tsd, struct g_raid_disk *tdisk)
261889b17223SAlexander Motin {
261989b17223SAlexander Motin struct g_raid_softc *sc;
262089b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
262189b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
262289b17223SAlexander Motin struct g_raid_subdisk *sd;
262389b17223SAlexander Motin
262489b17223SAlexander Motin sc = md->mdo_softc;
262589b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
262689b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)tdisk->d_md_data;
262789b17223SAlexander Motin
262889b17223SAlexander Motin /* We can't fail disk that is not a part of array now. */
262989b17223SAlexander Motin if (pd->pd_disk_pos < 0)
263089b17223SAlexander Motin return (-1);
263189b17223SAlexander Motin
263289b17223SAlexander Motin /*
263389b17223SAlexander Motin * Mark disk as failed in metadata and try to write that metadata
263489b17223SAlexander Motin * to the disk itself to prevent it's later resurrection as STALE.
263589b17223SAlexander Motin */
263689b17223SAlexander Motin mdi->mdio_meta->disk[pd->pd_disk_pos].flags = INTEL_F_FAILED;
263789b17223SAlexander Motin pd->pd_disk_meta.flags = INTEL_F_FAILED;
263889b17223SAlexander Motin g_raid_md_intel_print(mdi->mdio_meta);
263989b17223SAlexander Motin if (tdisk->d_consumer)
264089b17223SAlexander Motin intel_meta_write(tdisk->d_consumer, mdi->mdio_meta);
264189b17223SAlexander Motin
264289b17223SAlexander Motin /* Change states. */
264389b17223SAlexander Motin g_raid_change_disk_state(tdisk, G_RAID_DISK_S_FAILED);
264489b17223SAlexander Motin TAILQ_FOREACH(sd, &tdisk->d_subdisks, sd_next) {
264589b17223SAlexander Motin g_raid_change_subdisk_state(sd,
264689b17223SAlexander Motin G_RAID_SUBDISK_S_FAILED);
264789b17223SAlexander Motin g_raid_event_send(sd, G_RAID_SUBDISK_E_FAILED,
264889b17223SAlexander Motin G_RAID_EVENT_SUBDISK);
264989b17223SAlexander Motin }
265089b17223SAlexander Motin
265189b17223SAlexander Motin /* Write updated metadata to remaining disks. */
265289b17223SAlexander Motin g_raid_md_write_intel(md, NULL, NULL, tdisk);
265389b17223SAlexander Motin
265489b17223SAlexander Motin /* Check if anything left except placeholders. */
265589b17223SAlexander Motin if (g_raid_ndisks(sc, -1) ==
265689b17223SAlexander Motin g_raid_ndisks(sc, G_RAID_DISK_S_OFFLINE))
265789b17223SAlexander Motin g_raid_destroy_node(sc, 0);
265889b17223SAlexander Motin else
265989b17223SAlexander Motin g_raid_md_intel_refill(sc);
266089b17223SAlexander Motin return (0);
266189b17223SAlexander Motin }
266289b17223SAlexander Motin
266389b17223SAlexander Motin static int
g_raid_md_free_disk_intel(struct g_raid_md_object * md,struct g_raid_disk * disk)266489b17223SAlexander Motin g_raid_md_free_disk_intel(struct g_raid_md_object *md,
266589b17223SAlexander Motin struct g_raid_disk *disk)
266689b17223SAlexander Motin {
266789b17223SAlexander Motin struct g_raid_md_intel_perdisk *pd;
266889b17223SAlexander Motin
266989b17223SAlexander Motin pd = (struct g_raid_md_intel_perdisk *)disk->d_md_data;
267089b17223SAlexander Motin if (pd->pd_meta != NULL) {
267189b17223SAlexander Motin free(pd->pd_meta, M_MD_INTEL);
267289b17223SAlexander Motin pd->pd_meta = NULL;
267389b17223SAlexander Motin }
267489b17223SAlexander Motin free(pd, M_MD_INTEL);
267589b17223SAlexander Motin disk->d_md_data = NULL;
267689b17223SAlexander Motin return (0);
267789b17223SAlexander Motin }
267889b17223SAlexander Motin
267989b17223SAlexander Motin static int
g_raid_md_free_volume_intel(struct g_raid_md_object * md,struct g_raid_volume * vol)268026c538bcSAlexander Motin g_raid_md_free_volume_intel(struct g_raid_md_object *md,
268126c538bcSAlexander Motin struct g_raid_volume *vol)
268226c538bcSAlexander Motin {
268326c538bcSAlexander Motin struct g_raid_md_intel_pervolume *pv;
268426c538bcSAlexander Motin
268526c538bcSAlexander Motin pv = (struct g_raid_md_intel_pervolume *)vol->v_md_data;
268626c538bcSAlexander Motin free(pv, M_MD_INTEL);
268726c538bcSAlexander Motin vol->v_md_data = NULL;
268826c538bcSAlexander Motin return (0);
268926c538bcSAlexander Motin }
269026c538bcSAlexander Motin
269126c538bcSAlexander Motin static int
g_raid_md_free_intel(struct g_raid_md_object * md)269289b17223SAlexander Motin g_raid_md_free_intel(struct g_raid_md_object *md)
269389b17223SAlexander Motin {
269489b17223SAlexander Motin struct g_raid_md_intel_object *mdi;
269589b17223SAlexander Motin
269689b17223SAlexander Motin mdi = (struct g_raid_md_intel_object *)md;
269789b17223SAlexander Motin if (!mdi->mdio_started) {
269889b17223SAlexander Motin mdi->mdio_started = 0;
269989b17223SAlexander Motin callout_stop(&mdi->mdio_start_co);
270089b17223SAlexander Motin G_RAID_DEBUG1(1, md->mdo_softc,
270189b17223SAlexander Motin "root_mount_rel %p", mdi->mdio_rootmount);
270289b17223SAlexander Motin root_mount_rel(mdi->mdio_rootmount);
270389b17223SAlexander Motin mdi->mdio_rootmount = NULL;
270489b17223SAlexander Motin }
270589b17223SAlexander Motin if (mdi->mdio_meta != NULL) {
270689b17223SAlexander Motin free(mdi->mdio_meta, M_MD_INTEL);
270789b17223SAlexander Motin mdi->mdio_meta = NULL;
270889b17223SAlexander Motin }
270989b17223SAlexander Motin return (0);
271089b17223SAlexander Motin }
271189b17223SAlexander Motin
2712c89d2fbeSAlexander Motin G_RAID_MD_DECLARE(intel, "Intel");
2713