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 <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_NVIDIA, "md_nvidia_data", "GEOM_RAID NVIDIA metadata"); 508dab5b0mav 518dab5b0mavstruct nvidia_raid_conf { 528dab5b0mav uint8_t nvidia_id[8]; 538dab5b0mav#define NVIDIA_MAGIC "NVIDIA " 548dab5b0mav 558dab5b0mav uint32_t config_size; 568dab5b0mav uint32_t checksum; 578dab5b0mav uint16_t version; 588dab5b0mav uint8_t disk_number; 598dab5b0mav uint8_t dummy_0; 608dab5b0mav uint32_t total_sectors; 618dab5b0mav uint32_t sector_size; 628dab5b0mav uint8_t name[16]; 638dab5b0mav uint8_t revision[4]; 648dab5b0mav uint32_t disk_status; 658dab5b0mav 668dab5b0mav uint32_t magic_0; 678dab5b0mav#define NVIDIA_MAGIC0 0x00640044 688dab5b0mav 698dab5b0mav uint64_t volume_id[2]; 708dab5b0mav uint8_t state; 718dab5b0mav#define NVIDIA_S_IDLE 0 728dab5b0mav#define NVIDIA_S_INIT 2 738dab5b0mav#define NVIDIA_S_REBUILD 3 748dab5b0mav#define NVIDIA_S_UPGRADE 4 758dab5b0mav#define NVIDIA_S_SYNC 5 768dab5b0mav uint8_t array_width; 778dab5b0mav uint8_t total_disks; 788dab5b0mav uint8_t orig_array_width; 798dab5b0mav uint16_t type; 808dab5b0mav#define NVIDIA_T_RAID0 0x0080 818dab5b0mav#define NVIDIA_T_RAID1 0x0081 828dab5b0mav#define NVIDIA_T_RAID3 0x0083 838dab5b0mav#define NVIDIA_T_RAID5 0x0085 /* RLQ = 00/02? */ 848dab5b0mav#define NVIDIA_T_RAID5_SYM 0x0095 /* RLQ = 03 */ 858dab5b0mav#define NVIDIA_T_RAID10 0x008a 868dab5b0mav#define NVIDIA_T_RAID01 0x8180 878dab5b0mav#define NVIDIA_T_CONCAT 0x00ff 888dab5b0mav 898dab5b0mav uint16_t dummy_3; 908dab5b0mav uint32_t strip_sectors; 918dab5b0mav uint32_t strip_bytes; 928dab5b0mav uint32_t strip_shift; 938dab5b0mav uint32_t strip_mask; 948dab5b0mav uint32_t stripe_sectors; 958dab5b0mav uint32_t stripe_bytes; 968dab5b0mav uint32_t rebuild_lba; 978dab5b0mav uint32_t orig_type; 988dab5b0mav uint32_t orig_total_sectors; 998dab5b0mav uint32_t status; 1008dab5b0mav#define NVIDIA_S_BOOTABLE 0x00000001 1018dab5b0mav#define NVIDIA_S_DEGRADED 0x00000002 1028dab5b0mav 1038dab5b0mav uint32_t filler[98]; 1048dab5b0mav} __packed; 1058dab5b0mav 1068dab5b0mavstruct g_raid_md_nvidia_perdisk { 1078dab5b0mav struct nvidia_raid_conf *pd_meta; 1088dab5b0mav int pd_disk_pos; 1098dab5b0mav off_t pd_disk_size; 1108dab5b0mav}; 1118dab5b0mav 1128dab5b0mavstruct g_raid_md_nvidia_object { 1138dab5b0mav struct g_raid_md_object mdio_base; 1148dab5b0mav uint64_t mdio_volume_id[2]; 1158dab5b0mav struct nvidia_raid_conf *mdio_meta; 1168dab5b0mav struct callout mdio_start_co; /* STARTING state timer. */ 1178dab5b0mav int mdio_total_disks; 1188dab5b0mav int mdio_disks_present; 1198dab5b0mav int mdio_started; 1208dab5b0mav int mdio_incomplete; 1218dab5b0mav struct root_hold_token *mdio_rootmount; /* Root mount delay token. */ 1228dab5b0mav}; 1238dab5b0mav 1248dab5b0mavstatic g_raid_md_create_t g_raid_md_create_nvidia; 1258dab5b0mavstatic g_raid_md_taste_t g_raid_md_taste_nvidia; 1268dab5b0mavstatic g_raid_md_event_t g_raid_md_event_nvidia; 1278dab5b0mavstatic g_raid_md_ctl_t g_raid_md_ctl_nvidia; 1288dab5b0mavstatic g_raid_md_write_t g_raid_md_write_nvidia; 1298dab5b0mavstatic g_raid_md_fail_disk_t g_raid_md_fail_disk_nvidia; 1308dab5b0mavstatic g_raid_md_free_disk_t g_raid_md_free_disk_nvidia; 1318dab5b0mavstatic g_raid_md_free_t g_raid_md_free_nvidia; 1328dab5b0mav 1338dab5b0mavstatic kobj_method_t g_raid_md_nvidia_methods[] = { 1348dab5b0mav KOBJMETHOD(g_raid_md_create, g_raid_md_create_nvidia), 1358dab5b0mav KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_nvidia), 1368dab5b0mav KOBJMETHOD(g_raid_md_event, g_raid_md_event_nvidia), 1378dab5b0mav KOBJMETHOD(g_raid_md_ctl, g_raid_md_ctl_nvidia), 1388dab5b0mav KOBJMETHOD(g_raid_md_write, g_raid_md_write_nvidia), 1398dab5b0mav KOBJMETHOD(g_raid_md_fail_disk, g_raid_md_fail_disk_nvidia), 1408dab5b0mav KOBJMETHOD(g_raid_md_free_disk, g_raid_md_free_disk_nvidia), 1418dab5b0mav KOBJMETHOD(g_raid_md_free, g_raid_md_free_nvidia), 1428dab5b0mav { 0, 0 } 1438dab5b0mav}; 1448dab5b0mav 1458dab5b0mavstatic struct g_raid_md_class g_raid_md_nvidia_class = { 1468dab5b0mav "NVIDIA", 1478dab5b0mav g_raid_md_nvidia_methods, 1488dab5b0mav sizeof(struct g_raid_md_nvidia_object), 149db9e01amav .mdc_enable = 1, 1508dab5b0mav .mdc_priority = 100 1518dab5b0mav}; 1528dab5b0mav 1538dab5b0mavstatic int NVIDIANodeID = 1; 1548dab5b0mav 1558dab5b0mavstatic void 1568dab5b0mavg_raid_md_nvidia_print(struct nvidia_raid_conf *meta) 1578dab5b0mav{ 1588dab5b0mav 1598dab5b0mav if (g_raid_debug < 1) 1608dab5b0mav return; 1618dab5b0mav 1628dab5b0mav printf("********* ATA NVIDIA RAID Metadata *********\n"); 1638dab5b0mav printf("nvidia_id <%.8s>\n", meta->nvidia_id); 1648dab5b0mav printf("config_size %u\n", meta->config_size); 1658dab5b0mav printf("checksum 0x%08x\n", meta->checksum); 1668dab5b0mav printf("version 0x%04x\n", meta->version); 1678dab5b0mav printf("disk_number %d\n", meta->disk_number); 1688dab5b0mav printf("dummy_0 0x%02x\n", meta->dummy_0); 1698dab5b0mav printf("total_sectors %u\n", meta->total_sectors); 1708dab5b0mav printf("sector_size %u\n", meta->sector_size); 1718dab5b0mav printf("name <%.16s>\n", meta->name); 1728dab5b0mav printf("revision 0x%02x%02x%02x%02x\n", 1738dab5b0mav meta->revision[0], meta->revision[1], 1748dab5b0mav meta->revision[2], meta->revision[3]); 1758dab5b0mav printf("disk_status 0x%08x\n", meta->disk_status); 1768dab5b0mav printf("magic_0 0x%08x\n", meta->magic_0); 1778dab5b0mav printf("volume_id 0x%016jx%016jx\n", 1788dab5b0mav meta->volume_id[1], meta->volume_id[0]); 1798dab5b0mav printf("state 0x%02x\n", meta->state); 1808dab5b0mav printf("array_width %u\n", meta->array_width); 1818dab5b0mav printf("total_disks %u\n", meta->total_disks); 1828dab5b0mav printf("orig_array_width %u\n", meta->orig_array_width); 1838dab5b0mav printf("type 0x%04x\n", meta->type); 1848dab5b0mav printf("dummy_3 0x%04x\n", meta->dummy_3); 1858dab5b0mav printf("strip_sectors %u\n", meta->strip_sectors); 1868dab5b0mav printf("strip_bytes %u\n", meta->strip_bytes); 1878dab5b0mav printf("strip_shift %u\n", meta->strip_shift); 1888dab5b0mav printf("strip_mask 0x%08x\n", meta->strip_mask); 1898dab5b0mav printf("stripe_sectors %u\n", meta->stripe_sectors); 1908dab5b0mav printf("stripe_bytes %u\n", meta->stripe_bytes); 1918dab5b0mav printf("rebuild_lba %u\n", meta->rebuild_lba); 1928dab5b0mav printf("orig_type 0x%04x\n", meta->orig_type); 1938dab5b0mav printf("orig_total_sectors %u\n", meta->orig_total_sectors); 1948dab5b0mav printf("status 0x%08x\n", meta->status); 1958dab5b0mav printf("=================================================\n"); 1968dab5b0mav} 1978dab5b0mav 1988dab5b0mavstatic struct nvidia_raid_conf * 1998dab5b0mavnvidia_meta_copy(struct nvidia_raid_conf *meta) 2008dab5b0mav{ 2018dab5b0mav struct nvidia_raid_conf *nmeta; 2028dab5b0mav 2038dab5b0mav nmeta = malloc(sizeof(*meta), M_MD_NVIDIA, M_WAITOK); 2048dab5b0mav memcpy(nmeta, meta, sizeof(*meta)); 2058dab5b0mav return (nmeta); 2068dab5b0mav} 2078dab5b0mav 2088dab5b0mavstatic int 2098dab5b0mavnvidia_meta_translate_disk(struct nvidia_raid_conf *meta, int md_disk_pos) 2108dab5b0mav{ 2118dab5b0mav int disk_pos; 2128dab5b0mav 2138dab5b0mav if (md_disk_pos >= 0 && meta->type == NVIDIA_T_RAID01) { 2148dab5b0mav disk_pos = (md_disk_pos / meta->array_width) + 2158dab5b0mav (md_disk_pos % meta->array_width) * meta->array_width; 2168dab5b0mav } else 2178dab5b0mav disk_pos = md_disk_pos; 2188dab5b0mav return (disk_pos); 2198dab5b0mav} 2208dab5b0mav 2218dab5b0mavstatic void 2228dab5b0mavnvidia_meta_get_name(struct nvidia_raid_conf *meta, char *buf) 2238dab5b0mav{ 2248dab5b0mav int i; 2258dab5b0mav 2268dab5b0mav strncpy(buf, meta->name, 16); 2278dab5b0mav buf[16] = 0; 2288dab5b0mav for (i = 15; i >= 0; i--) { 2298dab5b0mav if (buf[i] > 0x20) 2308dab5b0mav break; 2318dab5b0mav buf[i] = 0; 2328dab5b0mav } 2338dab5b0mav} 2348dab5b0mav 2358dab5b0mavstatic void 2368dab5b0mavnvidia_meta_put_name(struct nvidia_raid_conf *meta, char *buf) 2378dab5b0mav{ 2388dab5b0mav 2398dab5b0mav memset(meta->name, 0x20, 16); 2408dab5b0mav memcpy(meta->name, buf, MIN(strlen(buf), 16)); 2418dab5b0mav} 2428dab5b0mav 2438dab5b0mavstatic struct nvidia_raid_conf * 2448dab5b0mavnvidia_meta_read(struct g_consumer *cp) 2458dab5b0mav{ 2468dab5b0mav struct g_provider *pp; 2478dab5b0mav struct nvidia_raid_conf *meta; 2488dab5b0mav char *buf; 2498dab5b0mav int error, i; 2508dab5b0mav uint32_t checksum, *ptr; 2518dab5b0mav 2528dab5b0mav pp = cp->provider; 2538dab5b0mav 2548dab5b0mav /* Read the anchor sector. */ 2558dab5b0mav buf = g_read_data(cp, 2568dab5b0mav pp->mediasize - 2 * pp->sectorsize, pp->sectorsize, &error); 2578dab5b0mav if (buf == NULL) { 2588dab5b0mav G_RAID_DEBUG(1, "Cannot read metadata from %s (error=%d).", 2598dab5b0mav pp->name, error); 2608dab5b0mav return (NULL); 2618dab5b0mav } 262f68d5demav meta = (struct nvidia_raid_conf *)buf; 2638dab5b0mav 2648dab5b0mav /* Check if this is an NVIDIA RAID struct */ 2658dab5b0mav if (strncmp(meta->nvidia_id, NVIDIA_MAGIC, strlen(NVIDIA_MAGIC))) { 2668dab5b0mav G_RAID_DEBUG(1, "NVIDIA signature check failed on %s", pp->name); 267f68d5demav g_free(buf); 2688dab5b0mav return (NULL); 2698dab5b0mav } 2708dab5b0mav if (meta->config_size > 128 || 2718dab5b0mav meta->config_size < 30) { 2728dab5b0mav G_RAID_DEBUG(1, "NVIDIA metadata size looks wrong: %d", 2738dab5b0mav meta->config_size); 274f68d5demav g_free(buf); 2758dab5b0mav return (NULL); 2768dab5b0mav } 277f68d5demav meta = malloc(sizeof(*meta), M_MD_NVIDIA, M_WAITOK); 278f68d5demav memcpy(meta, buf, min(sizeof(*meta), pp->sectorsize)); 279f68d5demav g_free(buf); 2808dab5b0mav 2818dab5b0mav /* Check metadata checksum. */ 2828dab5b0mav for (checksum = 0, ptr = (uint32_t *)meta, 2838dab5b0mav i = 0; i < meta->config_size; i++) 2848dab5b0mav checksum += *ptr++; 2858dab5b0mav if (checksum != 0) { 2868dab5b0mav G_RAID_DEBUG(1, "NVIDIA checksum check failed on %s", pp->name); 2878dab5b0mav free(meta, M_MD_NVIDIA); 2888dab5b0mav return (NULL); 2898dab5b0mav } 2908dab5b0mav 2918dab5b0mav /* Check volume state. */ 2928dab5b0mav if (meta->state != NVIDIA_S_IDLE && meta->state != NVIDIA_S_INIT && 2938dab5b0mav meta->state != NVIDIA_S_REBUILD && meta->state != NVIDIA_S_SYNC) { 2948dab5b0mav G_RAID_DEBUG(1, "NVIDIA unknown state on %s (0x%02x)", 2958dab5b0mav pp->name, meta->state); 2968dab5b0mav free(meta, M_MD_NVIDIA); 2978dab5b0mav return (NULL); 2988dab5b0mav } 2998dab5b0mav 300