18dab5b0mav/*- 2a82e3a8pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3a82e3a8pfg * 48dab5b0mav * Copyright (c) 2011 Alexander Motin <mav@FreeBSD.org> 5c283985mav * Copyright (c) 2000 - 2008 S��ren Schmidt <sos@FreeBSD.org> 68dab5b0mav * All rights reserved. 78dab5b0mav * 88dab5b0mav * Redistribution and use in source and binary forms, with or without 98dab5b0mav * modification, are permitted provided that the following conditions 108dab5b0mav * are met: 118dab5b0mav * 1. Redistributions of source code must retain the above copyright 128dab5b0mav * notice, this list of conditions and the following disclaimer. 138dab5b0mav * 2. Redistributions in binary form must reproduce the above copyright 148dab5b0mav * notice, this list of conditions and the following disclaimer in the 158dab5b0mav * documentation and/or other materials provided with the distribution. 168dab5b0mav * 178dab5b0mav * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 188dab5b0mav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198dab5b0mav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208dab5b0mav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 218dab5b0mav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228dab5b0mav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238dab5b0mav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248dab5b0mav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258dab5b0mav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268dab5b0mav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278dab5b0mav * SUCH DAMAGE. 288dab5b0mav */ 298dab5b0mav 308dab5b0mav#include <sys/cdefs.h> 318dab5b0mav__FBSDID("$FreeBSD$"); 328dab5b0mav 338dab5b0mav#include <sys/param.h> 348dab5b0mav#include <sys/bio.h> 358dab5b0mav#include <sys/endian.h> 368dab5b0mav#include <sys/kernel.h> 378dab5b0mav#include <sys/kobj.h> 388dab5b0mav#include <sys/limits.h> 398dab5b0mav#include <sys/lock.h> 408dab5b0mav#include <sys/malloc.h> 418dab5b0mav#include <sys/mutex.h> 428dab5b0mav#include <sys/systm.h> 438dab5b0mav#include <geom/geom.h> 4410d53fccem#include <geom/geom_dbg.h> 458dab5b0mav#include "geom/raid/g_raid.h" 468dab5b0mav#include "g_raid_md_if.h" 478dab5b0mav 488dab5b0mavstatic MALLOC_DEFINE(M_MD_PROMISE, "md_promise_data", "GEOM_RAID Promise metadata"); 498dab5b0mav 508dab5b0mav#define PROMISE_MAX_DISKS 8 518dab5b0mav#define PROMISE_MAX_SUBDISKS 2 528dab5b0mav#define PROMISE_META_OFFSET 14 538dab5b0mav 548dab5b0mavstruct promise_raid_disk { 558dab5b0mav uint8_t flags; /* Subdisk status. */ 568dab5b0mav#define PROMISE_F_VALID 0x01 578dab5b0mav#define PROMISE_F_ONLINE 0x02 588dab5b0mav#define PROMISE_F_ASSIGNED 0x04 598dab5b0mav#define PROMISE_F_SPARE 0x08 608dab5b0mav#define PROMISE_F_DUPLICATE 0x10 618dab5b0mav#define PROMISE_F_REDIR 0x20 628dab5b0mav#define PROMISE_F_DOWN 0x40 638dab5b0mav#define PROMISE_F_READY 0x80 648dab5b0mav 658dab5b0mav uint8_t number; /* Position in a volume. */ 668dab5b0mav uint8_t channel; /* ATA channel number. */ 678dab5b0mav uint8_t device; /* ATA device number. */ 688dab5b0mav uint64_t id __packed; /* Subdisk ID. */ 698dab5b0mav} __packed; 708dab5b0mav 718dab5b0mavstruct promise_raid_conf { 728dab5b0mav char promise_id[24]; 738dab5b0mav#define PROMISE_MAGIC "Promise Technology, Inc." 748dab5b0mav#define FREEBSD_MAGIC "FreeBSD ATA driver RAID " 758dab5b0mav 768dab5b0mav uint32_t dummy_0; 778dab5b0mav uint64_t magic_0; 788dab5b0mav#define PROMISE_MAGIC0(x) (((uint64_t)(x.channel) << 48) | \ 798dab5b0mav ((uint64_t)(x.device != 0) << 56)) 808dab5b0mav uint16_t magic_1; 818dab5b0mav uint32_t magic_2; 828dab5b0mav uint8_t filler1[470]; 838dab5b0mav 848dab5b0mav uint32_t integrity; 858dab5b0mav#define PROMISE_I_VALID 0x00000080 868dab5b0mav 878dab5b0mav struct promise_raid_disk disk; /* This subdisk info. */ 888dab5b0mav uint32_t disk_offset; /* Subdisk offset. */ 898dab5b0mav uint32_t disk_sectors; /* Subdisk size */ 90d3c13dfmav uint32_t disk_rebuild; /* Rebuild position. */ 918dab5b0mav uint16_t generation; /* Generation number. */ 928dab5b0mav uint8_t status; /* Volume status. */ 938dab5b0mav#define PROMISE_S_VALID 0x01 948dab5b0mav#define PROMISE_S_ONLINE 0x02 958dab5b0mav#define PROMISE_S_INITED 0x04 968dab5b0mav#define PROMISE_S_READY 0x08 978dab5b0mav#define PROMISE_S_DEGRADED 0x10 988dab5b0mav#define PROMISE_S_MARKED 0x20 998dab5b0mav#define PROMISE_S_MIGRATING 0x40 1008dab5b0mav#define PROMISE_S_FUNCTIONAL 0x80 1018dab5b0mav 1028dab5b0mav uint8_t type; /* Voluem type. */ 1038dab5b0mav#define PROMISE_T_RAID0 0x00 1048dab5b0mav#define PROMISE_T_RAID1 0x01 1058dab5b0mav#define PROMISE_T_RAID3 0x02 1068dab5b0mav#define PROMISE_T_RAID5 0x04 1078dab5b0mav#define PROMISE_T_SPAN 0x08 1088dab5b0mav#define PROMISE_T_JBOD 0x10 1098dab5b0mav 1108dab5b0mav uint8_t total_disks; /* Disks in this volume. */ 1118dab5b0mav uint8_t stripe_shift; /* Strip size. */ 1128dab5b0mav uint8_t array_width; /* Number of RAID0 stripes. */ 1138dab5b0mav uint8_t array_number; /* Global volume number. */ 1148dab5b0mav uint32_t total_sectors; /* Volume size. */ 1158dab5b0mav uint16_t cylinders; /* Volume geometry: C. */ 1168dab5b0mav uint8_t heads; /* Volume geometry: H. */ 1178dab5b0mav uint8_t sectors; /* Volume geometry: S. */ 1188dab5b0mav uint64_t volume_id __packed; /* Volume ID, */ 1198dab5b0mav struct promise_raid_disk disks[PROMISE_MAX_DISKS]; 1208dab5b0mav /* Subdisks in this volume. */ 1218dab5b0mav char name[32]; /* Volume label. */ 1228dab5b0mav 1238dab5b0mav uint32_t filler2[8]; 1248dab5b0mav uint32_t magic_3; /* Something related to rebuild. */ 1258dab5b0mav uint64_t rebuild_lba64; /* Per-volume rebuild position. */ 1268dab5b0mav uint32_t magic_4; 1278dab5b0mav uint32_t magic_5; 128a4f906fmav uint32_t total_sectors_high; 129d3c13dfmav uint8_t magic_6; 130d3c13dfmav uint8_t sector_size; 131d3c13dfmav uint16_t magic_7; 13228491a8mav uint32_t magic_8[31]; 13328491a8mav uint32_t backup_time; 134d3c13dfmav uint16_t magic_9; 135d3c13dfmav uint32_t disk_offset_high; 136d3c13dfmav uint32_t disk_sectors_high; 137d3c13dfmav uint32_t disk_rebuild_high; 138d3c13dfmav uint16_t magic_10; 139d3c13dfmav uint32_t magic_11[3]; 140d3c13dfmav uint32_t filler3[284]; 1418dab5b0mav uint32_t checksum; 1428dab5b0mav} __packed; 1438dab5b0mav 1448dab5b0mavstruct g_raid_md_promise_perdisk { 1458dab5b0mav int pd_updated; 1468dab5b0mav int pd_subdisks; 1478dab5b0mav struct promise_raid_conf *pd_meta[PROMISE_MAX_SUBDISKS]; 1488dab5b0mav}; 1498dab5b0mav 1508dab5b0mavstruct g_raid_md_promise_pervolume { 1518dab5b0mav struct promise_raid_conf *pv_meta; 1528dab5b0mav uint64_t pv_id; 1538dab5b0mav uint16_t pv_generation; 1548dab5b0mav int pv_disks_present; 1558dab5b0mav int pv_started; 1568dab5b0mav struct callout pv_start_co; /* STARTING state timer. */ 1578dab5b0mav}; 1588dab5b0mav 1598dab5b0mavstatic g_raid_md_create_t g_raid_md_create_promise; 1608dab5b0mavstatic g_raid_md_taste_t g_raid_md_taste_promise; 1618dab5b0mavstatic g_raid_md_event_t g_raid_md_event_promise; 1628dab5b0mavstatic g_raid_md_volume_event_t g_raid_md_volume_event_promise; 1638dab5b0mavstatic g_raid_md_ctl_t g_raid_md_ctl_promise; 1648dab5b0mavstatic g_raid_md_write_t g_raid_md_write_promise; 1658dab5b0mavstatic g_raid_md_fail_disk_t g_raid_md_fail_disk_promise; 1668dab5b0mavstatic g_raid_md_free_disk_t g_raid_md_free_disk_promise; 1678dab5b0mavstatic g_raid_md_free_volume_t g_raid_md_free_volume_promise; 1688dab5b0mavstatic g_raid_md_free_t g_raid_md_free_promise; 1698dab5b0mav 1708dab5b0mavstatic kobj_method_t g_raid_md_promise_methods[] = { 1718dab5b0mav KOBJMETHOD(g_raid_md_create, g_raid_md_create_promise), 1728dab5b0mav KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_promise), 1738dab5b0mav KOBJMETHOD(g_raid_md_event, g_raid_md_event_promise), 1748dab5b0mav KOBJMETHOD(g_raid_md_volume_event, g_raid_md_volume_event_promise), 1758dab5b0mav KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_promise), 1768dab5b0mav KOBJMETHOD(g_raid_md_write, g_raid_md_write_promise), 1778dab5b0mav KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_promise), 1788dab5b0mav KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_promise), 1798dab5b0mav KOBJMETHOD(g_raid_md_free_volume, g_raid_md_free_volume_promise), 1808dab5b0mav KOBJMETHOD(g_raid_md_free, g_raid_md_free_promise), 1818dab5b0mav { 0, 0 } 1828dab5b0mav}; 1838dab5b0mav 1848dab5b0mavstatic struct g_raid_md_class g_raid_md_promise_class = { 1858dab5b0mav "Promise", 1868dab5b0mav g_raid_md_promise_methods, 1878dab5b0mav sizeof(struct g_raid_md_object), 188db9e01amav .mdc_enable = 1, 1898dab5b0mav .mdc_priority = 100 1908dab5b0mav}; 1918dab5b0mav 1928dab5b0mavstatic void 1938dab5b0mavg_raid_md_promise_print(struct promise_raid_conf *meta) 1948dab5b0mav{ 1958dab5b0mav int i; 1968dab5b0mav 1978dab5b0mav if (g_raid_debug < 1) 1988dab5b0mav return; 1998dab5b0mav 2008dab5b0mav printf("********* ATA Promise Metadata *********\n"); 2018dab5b0mav printf("promise_id <%.24s>\n", meta->promise_id); 2028dab5b0mav printf("disk %02x %02x %02x %02x %016jx\n", 2038dab5b0mav meta->disk.flags, meta->disk.number, meta->disk.channel, 2048dab5b0mav meta->disk.device, meta->disk.id); 2058dab5b0mav printf("disk_offset %u\n", meta->disk_offset); 2068dab5b0mav printf("disk_sectors %u\n", meta->disk_sectors); 207d3c13dfmav printf("disk_rebuild %u\n", meta->disk_rebuild); 2088dab5b0mav printf("generation %u\n", meta->generation); 2098dab5b0mav printf("status 0x%02x\n", meta->status); 2108dab5b0mav printf("type %u\n", meta->type); 2118dab5b0mav printf("total_disks %u\n", meta->total_disks); 2128dab5b0mav printf("stripe_shift %u\n", meta->stripe_shift); 2138dab5b0mav printf("array_width %u\n", meta->array_width); 2148dab5b0mav printf("array_number %u\n", meta->array_number); 2158dab5b0mav printf("total_sectors %u\n", meta->total_sectors); 2168dab5b0mav printf("cylinders %u\n", meta->cylinders); 2178dab5b0mav printf("heads %u\n", meta->heads); 2188dab5b0mav printf("sectors %u\n", meta->sectors); 2198dab5b0mav printf("volume_id 0x%016jx\n", meta->volume_id); 2208dab5b0mav printf("disks:\n"); 2218dab5b0mav for (i = 0; i < PROMISE_MAX_DISKS; i++ ) { 2228dab5b0mav printf(" %02x %02x %02x %02x %016jx\n", 2238dab5b0mav meta->disks[i].flags, meta->disks[i].number, 2248dab5b0mav meta->disks[i].channel, meta->disks[i].device, 2258dab5b0mav meta->disks[i].id); 2268dab5b0mav } 2278dab5b0mav printf("name <%.32s>\n", meta->name); 2288dab5b0mav printf("magic_3 0x%08x\n", meta->magic_3); 2298dab5b0mav printf("rebuild_lba64 %ju\n", meta->rebuild_lba64); 2308dab5b0mav printf("magic_4 0x%08x\n", meta->magic_4); 2318dab5b0mav printf("magic_5 0x%08x\n", meta->magic_5); 232a4f906fmav printf("total_sectors_high 0x%08x\n", meta->total_sectors_high); 233d3c13dfmav printf("sector_size %u\n", meta->sector_size); 23428491a8mav printf("backup_time %d\n", meta->backup_time); 235d3c13dfmav printf("disk_offset_high 0x%08x\n", meta->disk_offset_high); 236d3c13dfmav printf("disk_sectors_high 0x%08x\n", meta->disk_sectors_high); 237d3c13dfmav printf("disk_rebuild_high 0x%08x\n", meta->disk_rebuild_high); 2388dab5b0mav printf("=================================================\n"); 2398dab5b0mav} 2408dab5b0mav 2418dab5b0mavstatic struct promise_raid_conf * 2428dab5b0mavpromise_meta_copy(struct promise_raid_conf *meta) 2438dab5b0mav{ 2448dab5b0mav struct promise_raid_conf *nmeta; 2458dab5b0mav 2468dab5b0mav nmeta = malloc(sizeof(*nmeta), M_MD_PROMISE, M_WAITOK); 2478dab5b0mav memcpy(nmeta, meta, sizeof(*nmeta)); 2488dab5b0mav return (nmeta); 2498dab5b0mav} 2508dab5b0mav 2518dab5b0mavstatic int 2528dab5b0mavpromise_meta_find_disk(struct promise_raid_conf *meta, uint64_t id) 2538dab5b0mav{ 2548dab5b0mav int pos; 2558dab5b0mav 2568dab5b0mav for (pos = 0; pos < meta->total_disks; pos++) { 2578dab5b0mav if (meta->disks[pos].id == id) 2588dab5b0mav return (pos); 2598dab5b0mav } 2608dab5b0mav return (-1); 2618dab5b0mav} 2628dab5b0mav 2638dab5b0mavstatic int 2648dab5b0mavpromise_meta_unused_range(struct promise_raid_conf **metaarr, int nsd, 265d3c13dfmav off_t sectors, off_t *off, off_t *size) 2668dab5b0mav{ 267d3c13dfmav off_t coff, csize, tmp; 2688dab5b0mav int i, j; 2698dab5b0mav 2708dab5b0mav sectors -= 131072; 2718dab5b0mav *off = 0; 2728dab5b0mav *size = 0; 2738dab5b0mav coff = 0; 2748dab5b0mav csize = sectors; 2758dab5b0mav i = 0; 2768dab5b0mav while (1) { 2778dab5b0mav for (j = 0; j < nsd; j++) { 278d3c13dfmav tmp = ((off_t)metaarr[j]->disk_offset_high << 32) + 279d3c13dfmav metaarr[j]->disk_offset; 280d3c13dfmav if (tmp >= coff) 281d3c13dfmav csize = MIN(csize, tmp - coff); 2828dab5b0mav } 2838dab5b0mav if (csize > *size) { 2848dab5b0mav *off = coff; 2858dab5b0mav *size = csize; 2868dab5b0mav } 2878dab5b0mav if (i >= nsd) 2888dab5b0mav break; 289d3c13dfmav coff = ((off_t)metaarr[i]->disk_offset_high << 32) + 290d3c13dfmav metaarr[i]->disk_offset + 291d3c13dfmav ((off_t)metaarr[i]->disk_sectors_high << 32) + 292d3c13dfmav metaarr[i]->disk_sectors; 2938dab5b0mav csize = sectors - coff; 2948dab5b0mav i++; 295b63211epfg } 2968dab5b0mav return ((*size > 0) ? 1 : 0); 2978dab5b0mav} 2988dab5b0mav 2998dab5b0mavstatic int 3008dab5b0mavpromise_meta_translate_disk(struct g_raid_volume *vol, int md_disk_pos) 3018dab5b0mav{ 3028dab5b0mav int disk_pos, width; 3038dab5b0mav 3048dab5b0mav if (md_disk_pos >= 0 && vol->v_raid_level == G_RAID_VOLUME_RL_RAID1E) { 3058dab5b0mav width = vol->v_disks_count / 2; 3068dab5b0mav disk_pos = (md_disk_pos / width) + 3078dab5b0mav (md_disk_pos % width) * width; 3088dab5b0mav } else 3098dab5b0mav disk_pos = md_disk_pos; 3108dab5b0mav return (disk_pos); 3118dab5b0mav} 3128dab5b0mav 3138dab5b0mavstatic void 3148dab5b0mavpromise_meta_get_name(struct promise_raid_conf *meta, char *buf) 3158dab5b0mav{ 3168dab5b0mav int i; 3178dab5b0mav 3188dab5b0mav strncpy(buf, meta->name, 32); 319