18dab5b0mav/*- 2a82e3a8pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3a82e3a8pfg * 48dab5b0mav * Copyright (c) 2010 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 <sys/taskqueue.h> 448dab5b0mav#include <geom/geom.h> 4510d53fccem#include <geom/geom_dbg.h> 468dab5b0mav#include "geom/raid/g_raid.h" 478dab5b0mav#include "g_raid_md_if.h" 488dab5b0mav 498dab5b0mavstatic MALLOC_DEFINE(M_MD_JMICRON, "md_jmicron_data", "GEOM_RAID JMicron metadata"); 508dab5b0mav 518dab5b0mav#define JMICRON_MAX_DISKS 8 528dab5b0mav#define JMICRON_MAX_SPARE 2 538dab5b0mav 548dab5b0mavstruct jmicron_raid_conf { 558dab5b0mav u_int8_t signature[2]; 568dab5b0mav#define JMICRON_MAGIC "JM" 578dab5b0mav 588dab5b0mav u_int16_t version; 598dab5b0mav#define JMICRON_VERSION 0x0001 608dab5b0mav 618dab5b0mav u_int16_t checksum; 628dab5b0mav u_int8_t filler_1[10]; 638dab5b0mav u_int32_t disk_id; 648dab5b0mav u_int32_t offset; 658dab5b0mav u_int32_t disk_sectors_high; 668dab5b0mav u_int16_t disk_sectors_low; 678dab5b0mav u_int8_t filler_2[2]; 688dab5b0mav u_int8_t name[16]; 698dab5b0mav u_int8_t type; 708dab5b0mav#define JMICRON_T_RAID0 0 718dab5b0mav#define JMICRON_T_RAID1 1 728dab5b0mav#define JMICRON_T_RAID01 2 738dab5b0mav#define JMICRON_T_CONCAT 3 748dab5b0mav#define JMICRON_T_RAID5 5 758dab5b0mav 768dab5b0mav u_int8_t stripe_shift; 778dab5b0mav u_int16_t flags; 788dab5b0mav#define JMICRON_F_READY 0x0001 798dab5b0mav#define JMICRON_F_BOOTABLE 0x0002 808dab5b0mav#define JMICRON_F_BADSEC 0x0004 818dab5b0mav#define JMICRON_F_ACTIVE 0x0010 828dab5b0mav#define JMICRON_F_UNSYNC 0x0020 838dab5b0mav#define JMICRON_F_NEWEST 0x0040 848dab5b0mav 858dab5b0mav u_int8_t filler_3[4]; 868dab5b0mav u_int32_t spare[JMICRON_MAX_SPARE]; 878dab5b0mav u_int32_t disks[JMICRON_MAX_DISKS]; 888dab5b0mav#define JMICRON_DISK_MASK 0xFFFFFFF0 898dab5b0mav#define JMICRON_SEG_MASK 0x0000000F 908dab5b0mav u_int8_t filler_4[32]; 918dab5b0mav u_int8_t filler_5[384]; 928dab5b0mav}; 938dab5b0mav 948dab5b0mavstruct g_raid_md_jmicron_perdisk { 958dab5b0mav struct jmicron_raid_conf *pd_meta; 968dab5b0mav int pd_disk_pos; 978dab5b0mav int pd_disk_id; 988dab5b0mav off_t pd_disk_size; 998dab5b0mav}; 1008dab5b0mav 1018dab5b0mavstruct g_raid_md_jmicron_object { 1028dab5b0mav struct g_raid_md_object mdio_base; 1038dab5b0mav uint32_t mdio_config_id; 1048dab5b0mav struct jmicron_raid_conf *mdio_meta; 1058dab5b0mav struct callout mdio_start_co; /* STARTING state timer. */ 1068dab5b0mav int mdio_total_disks; 1078dab5b0mav int mdio_disks_present; 1088dab5b0mav int mdio_started; 1098dab5b0mav int mdio_incomplete; 1108dab5b0mav struct root_hold_token *mdio_rootmount; /* Root mount delay token. */ 1118dab5b0mav}; 1128dab5b0mav 1138dab5b0mavstatic g_raid_md_create_t g_raid_md_create_jmicron; 1148dab5b0mavstatic g_raid_md_taste_t g_raid_md_taste_jmicron; 1158dab5b0mavstatic g_raid_md_event_t g_raid_md_event_jmicron; 1168dab5b0mavstatic g_raid_md_ctl_t g_raid_md_ctl_jmicron; 1178dab5b0mavstatic g_raid_md_write_t g_raid_md_write_jmicron; 1188dab5b0mavstatic g_raid_md_fail_disk_t g_raid_md_fail_disk_jmicron; 1198dab5b0mavstatic g_raid_md_free_disk_t g_raid_md_free_disk_jmicron; 1208dab5b0mavstatic g_raid_md_free_t g_raid_md_free_jmicron; 1218dab5b0mav 1228dab5b0mavstatic kobj_method_t g_raid_md_jmicron_methods[] = { 1238dab5b0mav KOBJMETHOD(g_raid_md_create, g_raid_md_create_jmicron), 1248dab5b0mav KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_jmicron), 1258dab5b0mav KOBJMETHOD(g_raid_md_event, g_raid_md_event_jmicron), 1268dab5b0mav KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_jmicron), 1278dab5b0mav KOBJMETHOD(g_raid_md_write, g_raid_md_write_jmicron), 1288dab5b0mav KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_jmicron), 1298dab5b0mav KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_jmicron), 1308dab5b0mav KOBJMETHOD(g_raid_md_free, g_raid_md_free_jmicron), 1318dab5b0mav { 0, 0 } 1328dab5b0mav}; 1338dab5b0mav 1348dab5b0mavstatic struct g_raid_md_class g_raid_md_jmicron_class = { 1358dab5b0mav "JMicron", 1368dab5b0mav g_raid_md_jmicron_methods, 1378dab5b0mav sizeof(struct g_raid_md_jmicron_object), 138db9e01amav .mdc_enable = 1, 1398dab5b0mav .mdc_priority = 100 1408dab5b0mav}; 1418dab5b0mav 1428dab5b0mavstatic void 1438dab5b0mavg_raid_md_jmicron_print(struct jmicron_raid_conf *meta) 1448dab5b0mav{ 1458dab5b0mav int k; 1468dab5b0mav 1478dab5b0mav if (g_raid_debug < 1) 1488dab5b0mav return; 1498dab5b0mav 1508dab5b0mav printf("********* ATA JMicron RAID Metadata *********\n"); 1518dab5b0mav printf("signature <%c%c>\n", meta->signature[0], meta->signature[1]); 1528dab5b0mav printf("version %04x\n", meta->version); 1538dab5b0mav printf("checksum 0x%04x\n", meta->checksum); 1548dab5b0mav printf("disk_id 0x%08x\n", meta->disk_id); 1558dab5b0mav printf("offset 0x%08x\n", meta->offset); 1568dab5b0mav printf("disk_sectors_high 0x%08x\n", meta->disk_sectors_high); 1578dab5b0mav printf("disk_sectors_low 0x%04x\n", meta->disk_sectors_low); 1588dab5b0mav printf("name <%.16s>\n", meta->name); 1598dab5b0mav printf("type %d\n", meta->type); 1608dab5b0mav printf("stripe_shift %d\n", meta->stripe_shift); 1618dab5b0mav printf("flags %04x\n", meta->flags); 1628dab5b0mav printf("spare "); 1638dab5b0mav for (k = 0; k < JMICRON_MAX_SPARE; k++) 1648dab5b0mav printf(" 0x%08x", meta->spare[k]); 1658dab5b0mav printf("\n"); 1668dab5b0mav printf("disks "); 1678dab5b0mav for (k = 0; k < JMICRON_MAX_DISKS; k++) 1688dab5b0mav printf(" 0x%08x", meta->disks[k]); 1698dab5b0mav printf("\n"); 1708dab5b0mav printf("=================================================\n"); 1718dab5b0mav} 1728dab5b0mav 1738dab5b0mavstatic struct jmicron_raid_conf * 1748dab5b0mavjmicron_meta_copy(struct jmicron_raid_conf *meta) 1758dab5b0mav{ 1768dab5b0mav struct jmicron_raid_conf *nmeta; 1778dab5b0mav 1788dab5b0mav nmeta = malloc(sizeof(*meta), M_MD_JMICRON, M_WAITOK); 1798dab5b0mav memcpy(nmeta, meta, sizeof(*meta)); 1808dab5b0mav return (nmeta); 1818dab5b0mav} 1828dab5b0mav 1838dab5b0mavstatic int 1848dab5b0mavjmicron_meta_total_disks(struct jmicron_raid_conf *meta) 1858dab5b0mav{ 1868dab5b0mav int pos; 1878dab5b0mav 1888dab5b0mav for (pos = 0; pos < JMICRON_MAX_DISKS; pos++) { 1898dab5b0mav if (meta->disks[pos] == 0) 1908dab5b0mav break; 1918dab5b0mav } 1928dab5b0mav return (pos); 1938dab5b0mav} 1948dab5b0mav 1958dab5b0mavstatic int 1968dab5b0mavjmicron_meta_total_spare(struct jmicron_raid_conf *meta) 1978dab5b0mav{ 1988dab5b0mav int pos, n; 1998dab5b0mav 2008dab5b0mav n = 0; 2018dab5b0mav for (pos = 0; pos < JMICRON_MAX_SPARE; pos++) { 2028dab5b0mav if (meta->spare[pos] != 0) 2038dab5b0mav n++; 2048dab5b0mav } 2058dab5b0mav return (n); 2068dab5b0mav} 2078dab5b0mav 2088dab5b0mav/* 2098dab5b0mav * Generate fake Configuration ID based on disk IDs. 2108dab5b0mav * Note: it will change after each disk set change. 2118dab5b0mav */ 2128dab5b0mavstatic uint32_t 2138dab5b0mavjmicron_meta_config_id(struct jmicron_raid_conf *meta) 2148dab5b0mav{ 2158dab5b0mav int pos; 2168dab5b0mav uint32_t config_id; 2178dab5b0mav 2188dab5b0mav config_id = 0; 2198dab5b0mav for (pos = 0; pos < JMICRON_MAX_DISKS; pos++) 2208dab5b0mav config_id += meta->disks[pos] << pos; 2218dab5b0mav return (config_id); 2228dab5b0mav} 2238dab5b0mav 2248dab5b0mavstatic void 2258dab5b0mavjmicron_meta_get_name(struct jmicron_raid_conf *meta, char *buf) 2268dab5b0mav{ 2278dab5b0mav int i; 2288dab5b0mav 2298dab5b0mav strncpy(buf, meta->name, 16); 2308dab5b0mav buf[16] = 0; 2318dab5b0mav for (i = 15; i >= 0; i--) { 2328dab5b0mav if (buf[i] > 0x20) 2338dab5b0mav break; 2348dab5b0mav buf[i] = 0; 2358dab5b0mav } 2368dab5b0mav} 2378dab5b0mav 2388dab5b0mavstatic void 2398dab5b0mavjmicron_meta_put_name(struct jmicron_raid_conf *meta, char *buf) 2408dab5b0mav{ 2418dab5b0mav 2428dab5b0mav memset(meta->name, 0x20, 16); 2438dab5b0mav memcpy(meta->name, buf, MIN(strlen(buf), 16)); 2448dab5b0mav} 2458dab5b0mav 2468dab5b0mavstatic int 2478dab5b0mavjmicron_meta_find_disk(struct jmicron_raid_conf *meta, uint32_t id) 2488dab5b0mav{ 2498dab5b0mav int pos; 2508dab5b0mav 2518dab5b0mav id &= JMICRON_DISK_MASK; 2528dab5b0mav for (pos = 0; pos < JMICRON_MAX_DISKS; pos++) { 2538dab5b0mav if ((meta->disks[pos] & JMICRON_DISK_MASK) == id) 2548dab5b0mav return (pos); 2558dab5b0mav } 2568dab5b0mav for (pos = 0; pos < JMICRON_MAX_SPARE; pos++) { 2578dab5b0mav if ((meta->spare[pos] & JMICRON_DISK_MASK) == id) 2588dab5b0mav return (-3); 2598dab5b0mav } 2608dab5b0mav return (-1); 2618dab5b0mav} 2628dab5b0mav 2638dab5b0mavstatic struct jmicron_raid_conf * 2648dab5b0mavjmicron_meta_read(struct g_consumer *cp) 2658dab5b0mav{ 2668dab5b0mav struct g_provider *pp; 2678dab5b0mav struct jmicron_raid_conf *meta; 2688dab5b0mav char *buf; 2698dab5b0mav int error, i; 2708dab5b0mav uint16_t checksum, *ptr; 2718dab5b0mav 2728dab5b0mav pp = cp->provider; 2738dab5b0mav 2748dab5b0mav /* Read the anchor sector. */ 2758dab5b0mav buf = g_read_data(cp, 2768dab5b0mav pp->mediasize - pp->sectorsize, pp->sectorsize, &error); 2778dab5b0mav if (buf == NULL) { 2788dab5b0mav G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).", 2798dab5b0mav pp->name, error); 2808dab5b0mav return (NULL); 2818dab5b0mav } 2828dab5b0mav meta = (struct jmicron_raid_conf *)buf; 2838dab5b0mav 2848dab5b0mav /* Check if this is an JMicron RAID struct */ 2858dab5b0mav if (strncmp(meta->signature, JMICRON_MAGIC, strlen(JMICRON_MAGIC))) { 2868dab5b0mav G_RAID_DEBUG(1, "JMicron signature check failed on %s", pp->name); 2878dab5b0mav g_free(buf); 2888dab5b0mav return (NULL); 2898dab5b0mav } 2908dab5b0mav meta = malloc(sizeof(*meta), M_MD_JMICRON, M_WAITOK); 2918dab5b0mav memcpy(meta, buf, min(sizeof(*meta), pp->sectorsize)); 2928dab5b0mav g_free(buf); 2938dab5b0mav 2948dab5b0mav /* Check metadata checksum. */ 2958dab5b0mav for (checksum = 0, ptr = (uint16_t *)meta, i = 0; i < 64; i++) 2968dab5b0mav checksum += *ptr++; 297