geom_pc98.c revision 114507
193354Sphk/*- 293354Sphk * Copyright (c) 2002 Poul-Henning Kamp 393354Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 493354Sphk * All rights reserved. 593354Sphk * 693354Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 793354Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 893354Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 993354Sphk * DARPA CHATS research program. 1093354Sphk * 1193354Sphk * Redistribution and use in source and binary forms, with or without 1293354Sphk * modification, are permitted provided that the following conditions 1393354Sphk * are met: 1493354Sphk * 1. Redistributions of source code must retain the above copyright 1593354Sphk * notice, this list of conditions and the following disclaimer. 1693354Sphk * 2. Redistributions in binary form must reproduce the above copyright 1793354Sphk * notice, this list of conditions and the following disclaimer in the 1893354Sphk * documentation and/or other materials provided with the distribution. 1993354Sphk * 2093354Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2193354Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2293354Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2393354Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2493354Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2593354Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2693354Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2793354Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2893354Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2993354Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3093354Sphk * SUCH DAMAGE. 3193354Sphk * 3293354Sphk * $FreeBSD: head/sys/geom/geom_pc98.c 114507 2003-05-02 06:34:51Z phk $ 3393354Sphk */ 3493354Sphk 3593354Sphk#include <sys/param.h> 36113013Sphk#include <sys/endian.h> 3793354Sphk#include <sys/systm.h> 3893354Sphk#include <sys/kernel.h> 39106559Snyan#include <sys/malloc.h> 4093354Sphk#include <sys/bio.h> 4193354Sphk#include <sys/lock.h> 4293354Sphk#include <sys/mutex.h> 43106559Snyan 44106559Snyan#include <sys/diskpc98.h> 4593354Sphk#include <geom/geom.h> 4693354Sphk#include <geom/geom_slice.h> 4793354Sphk 4897075Sphk#define PC98_CLASS_NAME "PC98" 4993354Sphk 5093354Sphkstruct g_pc98_softc { 51108591Snyan u_int fwsectors, fwheads, sectorsize; 52108591Snyan int type[NDOSPART]; 53108591Snyan u_char sec[8192]; 5493354Sphk}; 5593354Sphk 56108591Snyanstatic void 57108650Snyang_pc98_print(int i, struct pc98_partition *dp) 58108591Snyan{ 59108591Snyan char sname[17]; 60108591Snyan 61108591Snyan strncpy(sname, dp->dp_name, 16); 62108591Snyan sname[16] = '\0'; 63108591Snyan 64108591Snyan g_hexdump(dp, sizeof(dp[0])); 65108591Snyan printf("[%d] mid:%d(0x%x) sid:%d(0x%x)", 66108591Snyan i, dp->dp_mid, dp->dp_mid, dp->dp_sid, dp->dp_sid); 67108591Snyan printf(" s:%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); 68108591Snyan printf(" e:%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); 69108591Snyan printf(" sname:%s\n", sname); 70108591Snyan} 71108591Snyan 7293354Sphkstatic int 73108591Snyang_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec) 74108591Snyan{ 75108591Snyan int i, error; 76108591Snyan off_t s[NDOSPART], l[NDOSPART]; 77108650Snyan struct pc98_partition dp[NDOSPART]; 78108591Snyan 79108591Snyan g_topology_assert(); 80108591Snyan 81108591Snyan if (sec[0x1fe] != 0x55 || sec[0x1ff] != 0xaa) 82108591Snyan return (EBUSY); 83108591Snyan 84108591Snyan#if 0 85108591Snyan /* 86108591Snyan * XXX: Some sources indicate this is a magic sequence, but appearantly 87113292Sphk * XXX: it is not universal. Documentation would be wonderful to have. 88108591Snyan */ 89108591Snyan if (sec[4] != 'I' || sec[5] != 'P' || sec[6] != 'L' || sec[7] != '1') 90108591Snyan return (EBUSY); 91108591Snyan#endif 92108591Snyan 93108591Snyan for (i = 0; i < NDOSPART; i++) 94114414Snyan pc98_partition_dec( 95108650Snyan sec + 512 + i * sizeof(struct pc98_partition), &dp[i]); 96108591Snyan 97108591Snyan for (i = 0; i < NDOSPART; i++) { 98108591Snyan /* If start and end are identical it's bogus */ 99108591Snyan if (dp[i].dp_ssect == dp[i].dp_esect && 100108591Snyan dp[i].dp_shd == dp[i].dp_ehd && 101108591Snyan dp[i].dp_scyl == dp[i].dp_ecyl) 102108591Snyan s[i] = l[i] = 0; 103108591Snyan else if (dp[i].dp_ecyl == 0) 104108591Snyan s[i] = l[i] = 0; 105108591Snyan else { 106108591Snyan s[i] = (off_t)dp[i].dp_scyl * 107108591Snyan ms->fwsectors * ms->fwheads * ms->sectorsize; 108108591Snyan l[i] = (off_t)(dp[i].dp_ecyl - dp[i].dp_scyl + 1) * 109108591Snyan ms->fwsectors * ms->fwheads * ms->sectorsize; 110108591Snyan } 111108591Snyan if (bootverbose) { 112108591Snyan printf("PC98 Slice %d on %s:\n", i + 1, gp->name); 113108591Snyan g_pc98_print(i, dp + i); 114108591Snyan } 115113292Sphk if (s[i] < 0 || l[i] < 0) 116113292Sphk error = EBUSY; 117113292Sphk else 118113292Sphk error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 119108591Snyan s[i], l[i], ms->sectorsize, 120108591Snyan "%ss%d", gp->name, i + 1); 121108591Snyan if (error) 122108591Snyan return (error); 123108591Snyan } 124108591Snyan 125108591Snyan for (i = 0; i < NDOSPART; i++) { 126108591Snyan ms->type[i] = (dp[i].dp_sid << 8) | dp[i].dp_mid; 127108591Snyan g_slice_config(gp, i, G_SLICE_CONFIG_SET, s[i], l[i], 128108591Snyan ms->sectorsize, "%ss%d", gp->name, i + 1); 129108591Snyan } 130108591Snyan 131108591Snyan bcopy(sec, ms->sec, sizeof (ms->sec)); 132108591Snyan 133108591Snyan return (0); 134108591Snyan} 135108591Snyan 136108591Snyanstatic void 137112989Sphkg_pc98_ioctl(void *arg, int flag) 138108591Snyan{ 139108591Snyan struct bio *bp; 140108591Snyan struct g_geom *gp; 141108591Snyan struct g_slicer *gsp; 142108591Snyan struct g_pc98_softc *ms; 143108591Snyan struct g_ioctl *gio; 144108591Snyan struct g_consumer *cp; 145108591Snyan u_char *sec; 146108591Snyan int error; 147108591Snyan 148108591Snyan bp = arg; 149112989Sphk if (flag == EV_CANCEL) { 150112989Sphk g_io_deliver(bp, ENXIO); 151112989Sphk return; 152112989Sphk } 153108591Snyan gp = bp->bio_to->geom; 154108591Snyan gsp = gp->softc; 155108591Snyan ms = gsp->softc; 156108591Snyan gio = (struct g_ioctl *)bp->bio_data; 157108591Snyan 158108591Snyan /* The disklabel to set is the ioctl argument. */ 159108591Snyan sec = gio->data; 160108591Snyan 161108591Snyan error = g_pc98_modify(gp, ms, sec); 162108591Snyan if (error) { 163108591Snyan g_io_deliver(bp, error); 164108591Snyan return; 165108591Snyan } 166108591Snyan cp = LIST_FIRST(&gp->consumer); 167108591Snyan error = g_write_data(cp, 0, sec, 8192); 168108591Snyan g_io_deliver(bp, error); 169108591Snyan} 170108591Snyan 171108591Snyanstatic int 17293354Sphkg_pc98_start(struct bio *bp) 17393354Sphk{ 174106559Snyan struct g_provider *pp; 17593354Sphk struct g_geom *gp; 176106559Snyan struct g_pc98_softc *mp; 17793354Sphk struct g_slicer *gsp; 178108591Snyan struct g_ioctl *gio; 179108591Snyan int idx, error; 18093354Sphk 181106559Snyan pp = bp->bio_to; 182107953Sphk idx = pp->index; 183106559Snyan gp = pp->geom; 18493354Sphk gsp = gp->softc; 185106559Snyan mp = gsp->softc; 186106559Snyan if (bp->bio_cmd == BIO_GETATTR) { 187107953Sphk if (g_handleattr_int(bp, "PC98::type", mp->type[idx])) 188106559Snyan return (1); 189106559Snyan if (g_handleattr_off_t(bp, "PC98::offset", 190107953Sphk gsp->slices[idx].offset)) 191106559Snyan return (1); 192106559Snyan } 193108591Snyan 194108591Snyan /* We only handle ioctl(2) requests of the right format. */ 195108591Snyan if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 196108591Snyan return (0); 197108591Snyan else if (bp->bio_length != sizeof(*gio)) 198108591Snyan return (0); 199108591Snyan /* Get hold of the ioctl parameters. */ 200108591Snyan gio = (struct g_ioctl *)bp->bio_data; 201108591Snyan 202108591Snyan switch (gio->cmd) { 203108591Snyan case DIOCSPC98: 204108591Snyan /* 205108591Snyan * These we cannot do without the topology lock and some 206108591Snyan * some I/O requests. Ask the event-handler to schedule 207108591Snyan * us in a less restricted environment. 208108591Snyan */ 209113937Sphk error = g_post_event(g_pc98_ioctl, bp, M_NOWAIT, gp, NULL); 210108591Snyan if (error) 211108591Snyan g_io_deliver(bp, error); 212108591Snyan /* 213108591Snyan * We must return non-zero to indicate that we will deal 214108591Snyan * with this bio, even though we have not done so yet. 215108591Snyan */ 216108591Snyan return (1); 217108591Snyan default: 218108591Snyan return (0); 219108591Snyan } 220108591Snyan 22193354Sphk return (0); 22293354Sphk} 22393354Sphk 22493354Sphkstatic void 225107953Sphkg_pc98_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 226106559Snyan struct g_consumer *cp __unused, struct g_provider *pp) 22793354Sphk{ 228106559Snyan struct g_pc98_softc *mp; 229106559Snyan struct g_slicer *gsp; 230108650Snyan struct pc98_partition dp; 231107012Snyan char sname[17]; 23293354Sphk 233106559Snyan gsp = gp->softc; 234106559Snyan mp = gsp->softc; 23593354Sphk g_slice_dumpconf(sb, indent, gp, cp, pp); 236106559Snyan if (pp != NULL) { 237114414Snyan pc98_partition_dec( 238108591Snyan mp->sec + 512 + 239108650Snyan pp->index * sizeof(struct pc98_partition), &dp); 240108591Snyan strncpy(sname, dp.dp_name, 16); 241107012Snyan sname[16] = '\0'; 242107012Snyan if (indent == NULL) { 243106559Snyan sbuf_printf(sb, " ty %d", mp->type[pp->index]); 244107012Snyan sbuf_printf(sb, " sn %s", sname); 245107012Snyan } else { 246106559Snyan sbuf_printf(sb, "%s<type>%d</type>\n", indent, 247106559Snyan mp->type[pp->index]); 248107012Snyan sbuf_printf(sb, "%s<sname>%s</sname>\n", indent, 249107012Snyan sname); 250107012Snyan } 251106559Snyan } 25293354Sphk} 25393354Sphk 25493354Sphkstatic struct g_geom * 25593354Sphkg_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) 25693354Sphk{ 25793354Sphk struct g_geom *gp; 25893354Sphk struct g_consumer *cp; 259108591Snyan int error; 26093354Sphk struct g_pc98_softc *ms; 26194287Sphk struct g_slicer *gsp; 262106559Snyan u_int fwsectors, fwheads, sectorsize; 263106559Snyan u_char *buf; 26493354Sphk 26593354Sphk g_trace(G_T_TOPOLOGY, "g_pc98_taste(%s,%s)", mp->name, pp->name); 26693354Sphk g_topology_assert(); 26793354Sphk if (flags == G_TF_NORMAL && 26893354Sphk !strcmp(pp->geom->class->name, PC98_CLASS_NAME)) 26993354Sphk return (NULL); 270106559Snyan gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_pc98_start); 27193354Sphk if (gp == NULL) 27293354Sphk return (NULL); 27394287Sphk gsp = gp->softc; 27493354Sphk g_topology_unlock(); 27593354Sphk gp->dumpconf = g_pc98_dumpconf; 276113285Sphk do { 27793354Sphk if (gp->rank != 2 && flags == G_TF_NORMAL) 27893354Sphk break; 279106559Snyan error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 280106559Snyan if (error || fwsectors == 0) { 281106559Snyan fwsectors = 17; 282113292Sphk if (bootverbose) 283113292Sphk printf("g_pc98_taste: guessing %d sectors\n", 284113292Sphk fwsectors); 28593354Sphk } 286106559Snyan error = g_getattr("GEOM::fwheads", cp, &fwheads); 287106559Snyan if (error || fwheads == 0) { 288106559Snyan fwheads = 8; 289113292Sphk if (bootverbose) 290113292Sphk printf("g_pc98_taste: guessing %d heads\n", 291113292Sphk fwheads); 29293354Sphk } 293106559Snyan sectorsize = cp->provider->sectorsize; 294106559Snyan if (sectorsize < 512) 295106559Snyan break; 296108591Snyan buf = g_read_data(cp, 0, 8192, &error); 29793354Sphk if (buf == NULL || error != 0) 29893354Sphk break; 299108591Snyan ms->fwsectors = fwsectors; 300108591Snyan ms->fwheads = fwheads; 301108591Snyan ms->sectorsize = sectorsize; 302108591Snyan g_topology_lock(); 303108591Snyan g_pc98_modify(gp, ms, buf); 304108591Snyan g_topology_unlock(); 305106559Snyan g_free(buf); 30693354Sphk break; 307113285Sphk } while (0); 30893354Sphk g_topology_lock(); 309107956Sphk g_access_rel(cp, -1, 0, 0); 310107956Sphk if (LIST_EMPTY(&gp->provider)) { 311114507Sphk g_slice_spoiled(cp); 312107956Sphk return (NULL); 313106559Snyan } 314107956Sphk return (gp); 31593354Sphk} 31693354Sphk 31793354Sphkstatic struct g_class g_pc98_class = { 318112552Sphk .name = PC98_CLASS_NAME, 319112552Sphk .taste = g_pc98_taste, 32098066Sphk G_CLASS_INITIALIZER 32193354Sphk}; 32293354Sphk 32393354SphkDECLARE_GEOM_CLASS(g_pc98_class, g_pc98); 324