geom_pc98.c revision 133314
157429Smarkm/*-
265668Skris * Copyright (c) 2002 Poul-Henning Kamp
365668Skris * Copyright (c) 2002 Networks Associates Technology, Inc.
460573Skris * All rights reserved.
565668Skris *
665668Skris * This software was developed for the FreeBSD Project by Poul-Henning Kamp
760573Skris * and NAI Labs, the Security Research Division of Network Associates, Inc.
857429Smarkm * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
960573Skris * DARPA CHATS research program.
1065668Skris *
1165668Skris * Redistribution and use in source and binary forms, with or without
1265668Skris * modification, are permitted provided that the following conditions
1365668Skris * are met:
1465668Skris * 1. Redistributions of source code must retain the above copyright
1565668Skris *    notice, this list of conditions and the following disclaimer.
1665668Skris * 2. Redistributions in binary form must reproduce the above copyright
1776259Sgreen *    notice, this list of conditions and the following disclaimer in the
1876259Sgreen *    documentation and/or other materials provided with the distribution.
1965668Skris *
2065668Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2165668Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2265668Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2365668Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2465668Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2565668Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2665668Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2765668Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2865668Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2965668Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3065668Skris * SUCH DAMAGE.
3165668Skris */
3265668Skris
3365668Skris#include <sys/cdefs.h>
3465668Skris__FBSDID("$FreeBSD: head/sys/geom/geom_pc98.c 133314 2004-08-08 06:49:07Z phk $");
3565668Skris
3665668Skris#include <sys/param.h>
3765668Skris#include <sys/endian.h>
3865668Skris#include <sys/systm.h>
3965668Skris#include <sys/kernel.h>
4057429Smarkm#include <sys/malloc.h>
4157429Smarkm#include <sys/bio.h>
4265668Skris#include <sys/lock.h>
4365668Skris#include <sys/mutex.h>
4457429Smarkm
4557429Smarkm#include <sys/diskpc98.h>
4657429Smarkm#include <geom/geom.h>
4757429Smarkm#include <geom/geom_slice.h>
4857429Smarkm
4957429Smarkm#define PC98_CLASS_NAME "PC98"
5057429Smarkm
5157429Smarkmstruct g_pc98_softc {
5257429Smarkm	u_int fwsectors, fwheads, sectorsize;
5357429Smarkm	int type[NDOSPART];
5457429Smarkm	u_char sec[8192];
55124211Sdes};
5657429Smarkm
5757429Smarkmstatic void
5857429Smarkmg_pc98_print(int i, struct pc98_partition *dp)
5957429Smarkm{
6057429Smarkm	char sname[17];
6157429Smarkm
6257429Smarkm	strncpy(sname, dp->dp_name, 16);
6357429Smarkm	sname[16] = '\0';
6457429Smarkm
6557429Smarkm	hexdump(dp, sizeof(dp[0]), NULL, 0);
6657429Smarkm	printf("[%d] mid:%d(0x%x) sid:%d(0x%x)",
6757429Smarkm	       i, dp->dp_mid, dp->dp_mid, dp->dp_sid, dp->dp_sid);
6857429Smarkm	printf(" s:%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect);
6957429Smarkm	printf(" e:%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect);
7057429Smarkm	printf(" sname:%s\n", sname);
7157429Smarkm}
7257429Smarkm
7357429Smarkmstatic int
74137019Sdesg_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec)
7557429Smarkm{
7657429Smarkm	int i, error;
7776259Sgreen	off_t s[NDOSPART], l[NDOSPART];
7876259Sgreen	struct pc98_partition dp[NDOSPART];
7976259Sgreen
8092555Sdes	g_topology_assert();
81113911Sdes
8257429Smarkm	if (sec[0x1fe] != 0x55 || sec[0x1ff] != 0xaa)
8398937Sdes		return (EBUSY);
8498937Sdes
85113911Sdes#if 0
8657429Smarkm	/*
8792555Sdes	 * XXX: Some sources indicate this is a magic sequence, but appearantly
8892555Sdes	 * XXX: it is not universal. Documentation would be wonderful to have.
8969587Sgreen	 */
90113911Sdes	if (sec[4] != 'I' || sec[5] != 'P' || sec[6] != 'L' || sec[7] != '1')
91126277Sdes		return (EBUSY);
9257429Smarkm#endif
9357429Smarkm
9457429Smarkm	for (i = 0; i < NDOSPART; i++)
9557429Smarkm		pc98_partition_dec(
9657429Smarkm			sec + 512 + i * sizeof(struct pc98_partition), &dp[i]);
9757429Smarkm
9857429Smarkm	for (i = 0; i < NDOSPART; i++) {
9957429Smarkm		/* If start and end are identical it's bogus */
10057429Smarkm		if (dp[i].dp_ssect == dp[i].dp_esect &&
10157429Smarkm		    dp[i].dp_shd == dp[i].dp_ehd &&
10265668Skris		    dp[i].dp_scyl == dp[i].dp_ecyl)
10376259Sgreen			s[i] = l[i] = 0;
10465668Skris		else if (dp[i].dp_ecyl == 0)
105113911Sdes			s[i] = l[i] = 0;
106124211Sdes		else {
107113911Sdes			s[i] = (off_t)dp[i].dp_scyl *
108124211Sdes				ms->fwsectors * ms->fwheads * ms->sectorsize;
109124211Sdes			l[i] = (off_t)(dp[i].dp_ecyl - dp[i].dp_scyl + 1) *
110124211Sdes				ms->fwsectors * ms->fwheads * ms->sectorsize;
111124211Sdes		}
112124211Sdes		if (bootverbose) {
113124211Sdes			printf("PC98 Slice %d on %s:\n", i + 1, gp->name);
114124211Sdes			g_pc98_print(i, dp + i);
115124211Sdes		}
116124211Sdes		if (s[i] < 0 || l[i] < 0)
11757429Smarkm			error = EBUSY;
11857429Smarkm		else
11957429Smarkm			error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
12057429Smarkm				       s[i], l[i], ms->sectorsize,
12157429Smarkm				       "%ss%d", gp->name, i + 1);
12257429Smarkm		if (error)
12360573Skris			return (error);
12465668Skris	}
12557429Smarkm
12657429Smarkm	for (i = 0; i < NDOSPART; i++) {
12757429Smarkm		ms->type[i] = (dp[i].dp_sid << 8) | dp[i].dp_mid;
12857429Smarkm		g_slice_config(gp, i, G_SLICE_CONFIG_SET, s[i], l[i],
12992555Sdes			       ms->sectorsize, "%ss%d", gp->name, i + 1);
13092555Sdes	}
13192555Sdes
13292555Sdes	bcopy(sec, ms->sec, sizeof (ms->sec));
13357429Smarkm
13457429Smarkm	return (0);
13557429Smarkm}
13657429Smarkm
13757429Smarkmstatic int
13857429Smarkmg_pc98_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td)
13957429Smarkm{
14057429Smarkm	struct g_geom *gp;
14157429Smarkm	struct g_pc98_softc *ms;
14257429Smarkm	struct g_slicer *gsp;
14357429Smarkm	struct g_consumer *cp;
14457429Smarkm	int error;
14557429Smarkm
14657429Smarkm	gp = pp->geom;
14757429Smarkm	gsp = gp->softc;
14857429Smarkm	ms = gsp->softc;
14957429Smarkm
150124211Sdes	switch(cmd) {
151113911Sdes	case DIOCSPC98: {
152113911Sdes		DROP_GIANT();
15357429Smarkm		g_topology_lock();
15457429Smarkm		/* Validate and modify our slicer instance to match. */
15557429Smarkm		error = g_pc98_modify(gp, ms, data);
15657429Smarkm		cp = LIST_FIRST(&gp->consumer);
15757429Smarkm		error = g_write_data(cp, 0, data, 8192);
15857429Smarkm		g_topology_unlock();
15957429Smarkm		PICKUP_GIANT();
16057429Smarkm		return(error);
16169587Sgreen	}
16269587Sgreen	default:
16392555Sdes		return (ENOIOCTL);
16492555Sdes	}
16592555Sdes}
16657429Smarkm
16769587Sgreenstatic int
16865668Skrisg_pc98_start(struct bio *bp)
16957429Smarkm{
170113911Sdes	struct g_provider *pp;
171113911Sdes	struct g_geom *gp;
17257429Smarkm	struct g_pc98_softc *mp;
17357429Smarkm	struct g_slicer *gsp;
17457429Smarkm	int idx;
17557429Smarkm
17657429Smarkm	pp = bp->bio_to;
17757429Smarkm	idx = pp->index;
178124211Sdes	gp = pp->geom;
179124211Sdes	gsp = gp->softc;
180124211Sdes	mp = gsp->softc;
18157429Smarkm	if (bp->bio_cmd == BIO_GETATTR) {
18257429Smarkm		if (g_handleattr_int(bp, "PC98::type", mp->type[idx]))
18357429Smarkm			return (1);
18457429Smarkm		if (g_handleattr_off_t(bp, "PC98::offset",
18557429Smarkm				       gsp->slices[idx].offset))
18657429Smarkm			return (1);
18757429Smarkm	}
18857429Smarkm
18957429Smarkm	return (0);
19057429Smarkm}
19157429Smarkm
19257429Smarkmstatic void
19357429Smarkmg_pc98_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
19457429Smarkm		struct g_consumer *cp __unused, struct g_provider *pp)
19557429Smarkm{
19657429Smarkm	struct g_pc98_softc *mp;
19757429Smarkm	struct g_slicer *gsp;
19857429Smarkm	struct pc98_partition dp;
19957429Smarkm	char sname[17];
20057429Smarkm
20157429Smarkm	gsp = gp->softc;
20257429Smarkm	mp = gsp->softc;
20357429Smarkm	g_slice_dumpconf(sb, indent, gp, cp, pp);
20457429Smarkm	if (pp != NULL) {
20557429Smarkm		pc98_partition_dec(
20657429Smarkm			mp->sec + 512 +
20757429Smarkm			pp->index * sizeof(struct pc98_partition), &dp);
20857429Smarkm		strncpy(sname, dp.dp_name, 16);
20957429Smarkm		sname[16] = '\0';
21057429Smarkm		if (indent == NULL) {
21157429Smarkm			sbuf_printf(sb, " ty %d", mp->type[pp->index]);
21257429Smarkm			sbuf_printf(sb, " sn %s", sname);
213124211Sdes		} else {
21457429Smarkm			sbuf_printf(sb, "%s<type>%d</type>\n", indent,
215113911Sdes				    mp->type[pp->index]);
216113911Sdes			sbuf_printf(sb, "%s<sname>%s</sname>\n", indent,
217113911Sdes				    sname);
21857429Smarkm		}
21957429Smarkm	}
22057429Smarkm}
221124211Sdes
22298937Sdesstatic struct g_geom *
22369587Sgreeng_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags)
22498675Sdes{
22592555Sdes	struct g_geom *gp;
22692555Sdes	struct g_consumer *cp;
22792555Sdes	int error;
22869587Sgreen	struct g_pc98_softc *ms;
22957429Smarkm	u_int fwsectors, fwheads, sectorsize;
230113911Sdes	u_char *buf;
23157429Smarkm
23257429Smarkm	g_trace(G_T_TOPOLOGY, "g_pc98_taste(%s,%s)", mp->name, pp->name);
233113911Sdes	g_topology_assert();
234113911Sdes	if (flags == G_TF_NORMAL &&
23557429Smarkm	    !strcmp(pp->geom->class->name, PC98_CLASS_NAME))
23657429Smarkm		return (NULL);
23769587Sgreen	gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_pc98_start);
23892555Sdes	if (gp == NULL)
23957429Smarkm		return (NULL);
24069587Sgreen	g_topology_unlock();
24169587Sgreen	do {
24269587Sgreen		if (gp->rank != 2 && flags == G_TF_NORMAL)
24392555Sdes			break;
24492555Sdes		error = g_getattr("GEOM::fwsectors", cp, &fwsectors);
24569587Sgreen		if (error || fwsectors == 0) {
24669587Sgreen			fwsectors = 17;
24792555Sdes			if (bootverbose)
24869587Sgreen				printf("g_pc98_taste: guessing %d sectors\n",
24969587Sgreen				    fwsectors);
25092555Sdes		}
25169587Sgreen		error = g_getattr("GEOM::fwheads", cp, &fwheads);
252113911Sdes		if (error || fwheads == 0) {
253113911Sdes			fwheads = 8;
254113911Sdes			if (bootverbose)
255113911Sdes				printf("g_pc98_taste: guessing %d heads\n",
256126277Sdes				    fwheads);
257113911Sdes		}
25857429Smarkm		sectorsize = cp->provider->sectorsize;
25957429Smarkm		if (sectorsize < 512)
26057429Smarkm			break;
26157429Smarkm		buf = g_read_data(cp, 0, 8192, &error);
26257429Smarkm		if (buf == NULL || error != 0)
26357429Smarkm			break;
26465668Skris		ms->fwsectors = fwsectors;
26569587Sgreen		ms->fwheads = fwheads;
26665668Skris		ms->sectorsize = sectorsize;
26769587Sgreen		g_topology_lock();
26892555Sdes		g_pc98_modify(gp, ms, buf);
26969587Sgreen		g_topology_unlock();
27069587Sgreen		g_free(buf);
27169587Sgreen		break;
272126277Sdes	} while (0);
27369587Sgreen	g_topology_lock();
27469587Sgreen	g_access(cp, -1, 0, 0);
27565668Skris	if (LIST_EMPTY(&gp->provider)) {
27657429Smarkm		g_slice_spoiled(cp);
27757429Smarkm		return (NULL);
27857429Smarkm	}
27957429Smarkm	return (gp);
28057429Smarkm}
28157429Smarkm
28257429Smarkmstatic struct g_class g_pc98_class = {
28357429Smarkm	.name = PC98_CLASS_NAME,
28457429Smarkm	.taste = g_pc98_taste,
28557429Smarkm	.dumpconf = g_pc98_dumpconf,
28657429Smarkm	.ioctl = g_pc98_ioctl,
28798937Sdes};
28898937Sdes
28998937SdesDECLARE_GEOM_CLASS(g_pc98_class, g_pc98);
29057429Smarkm