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