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