geom_pc98.c revision 138219
1145132Sanholt/*- 2145132Sanholt * Copyright (c) 2002 Poul-Henning Kamp 3145132Sanholt * Copyright (c) 2002 Networks Associates Technology, Inc. 4145132Sanholt * All rights reserved. 5145132Sanholt * 6145132Sanholt * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7145132Sanholt * and NAI Labs, the Security Research Division of Network Associates, Inc. 8145132Sanholt * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9145132Sanholt * DARPA CHATS research program. 10145132Sanholt * 11145132Sanholt * Redistribution and use in source and binary forms, with or without 12145132Sanholt * modification, are permitted provided that the following conditions 13145132Sanholt * are met: 14145132Sanholt * 1. Redistributions of source code must retain the above copyright 15145132Sanholt * notice, this list of conditions and the following disclaimer. 16145132Sanholt * 2. Redistributions in binary form must reproduce the above copyright 17145132Sanholt * notice, this list of conditions and the following disclaimer in the 18145132Sanholt * documentation and/or other materials provided with the distribution. 19145132Sanholt * 20145132Sanholt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21145132Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22145132Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23145132Sanholt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24145132Sanholt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25145132Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26152909Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27152909Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28152909Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29152909Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30152909Sanholt * SUCH DAMAGE. 31145132Sanholt */ 32145132Sanholt 33145132Sanholt#include <sys/cdefs.h> 34145132Sanholt__FBSDID("$FreeBSD: head/sys/geom/geom_pc98.c 138219 2004-11-30 08:00:14Z imp $"); 35145132Sanholt 36145132Sanholt#include <sys/param.h> 37145132Sanholt#include <sys/endian.h> 38182080Srnoland#include <sys/systm.h> 39182080Srnoland#include <sys/kernel.h> 40145132Sanholt#include <sys/malloc.h> 41145132Sanholt#include <sys/bio.h> 42145132Sanholt#include <sys/lock.h> 43145132Sanholt#include <sys/mutex.h> 44145132Sanholt 45145132Sanholt#include <sys/diskpc98.h> 46145132Sanholt#include <geom/geom.h> 47145132Sanholt#include <geom/geom_slice.h> 48145132Sanholt 49145132Sanholt#define PC98_CLASS_NAME "PC98" 50145132Sanholt 51145132Sanholtstruct g_pc98_softc { 52145132Sanholt u_int fwsectors, fwheads, sectorsize; 53145132Sanholt int type[NDOSPART]; 54145132Sanholt u_char sec[8192]; 55145132Sanholt}; 56145132Sanholt 57145132Sanholtstatic void 58145132Sanholtg_pc98_print(int i, struct pc98_partition *dp) 59145132Sanholt{ 60145132Sanholt char sname[17]; 61145132Sanholt 62145132Sanholt strncpy(sname, dp->dp_name, 16); 63145132Sanholt sname[16] = '\0'; 64145132Sanholt 65145132Sanholt hexdump(dp, sizeof(dp[0]), NULL, 0); 66182080Srnoland printf("[%d] mid:%d(0x%x) sid:%d(0x%x)", 67145132Sanholt i, dp->dp_mid, dp->dp_mid, dp->dp_sid, dp->dp_sid); 68145132Sanholt printf(" s:%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); 69145132Sanholt printf(" e:%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); 70145132Sanholt printf(" sname:%s\n", sname); 71145132Sanholt} 72145132Sanholt 73145132Sanholtstatic int 74145132Sanholtg_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec) 75145132Sanholt{ 76145132Sanholt int i, error; 77145132Sanholt off_t s[NDOSPART], l[NDOSPART]; 78145132Sanholt struct pc98_partition dp[NDOSPART]; 79145132Sanholt 80145132Sanholt g_topology_assert(); 81145132Sanholt 82145132Sanholt if (sec[0x1fe] != 0x55 || sec[0x1ff] != 0xaa) 83145132Sanholt return (EBUSY); 84145132Sanholt 85145132Sanholt#if 0 86145132Sanholt /* 87182080Srnoland * FreeBSD's boot0 IPL uses the name IPL1. This test initially was 88145132Sanholt * based on that observation. However, other boot loaders have use 89145132Sanholt * different names. A likely good test would be to test if the first 90145132Sanholt * 4 bytes are a jump to location 11 (or greater?) as well as the next 91145132Sanholt * 7 bytes being printable or with trailing NUL's. 92145132Sanholt */ 93145132Sanholt if (sec[4] != 'I' || sec[5] != 'P' || sec[6] != 'L' || sec[7] != '1') 94145132Sanholt return (EBUSY); 95145132Sanholt#endif 96145132Sanholt 97145132Sanholt for (i = 0; i < NDOSPART; i++) 98145132Sanholt pc98_partition_dec( 99145132Sanholt sec + 512 + i * sizeof(struct pc98_partition), &dp[i]); 100145132Sanholt 101145132Sanholt for (i = 0; i < NDOSPART; i++) { 102145132Sanholt /* If start and end are identical it's bogus */ 103145132Sanholt if (dp[i].dp_ssect == dp[i].dp_esect && 104145132Sanholt dp[i].dp_shd == dp[i].dp_ehd && 105145132Sanholt dp[i].dp_scyl == dp[i].dp_ecyl) 106145132Sanholt s[i] = l[i] = 0; 107145132Sanholt else if (dp[i].dp_ecyl == 0) 108182080Srnoland s[i] = l[i] = 0; 109145132Sanholt else { 110145132Sanholt s[i] = (off_t)dp[i].dp_scyl * 111145132Sanholt ms->fwsectors * ms->fwheads * ms->sectorsize; 112145132Sanholt l[i] = (off_t)(dp[i].dp_ecyl - dp[i].dp_scyl + 1) * 113145132Sanholt ms->fwsectors * ms->fwheads * ms->sectorsize; 114145132Sanholt } 115145132Sanholt if (bootverbose) { 116145132Sanholt printf("PC98 Slice %d on %s:\n", i + 1, gp->name); 117145132Sanholt g_pc98_print(i, dp + i); 118145132Sanholt } 119145132Sanholt if (s[i] < 0 || l[i] < 0) 120145132Sanholt error = EBUSY; 121145132Sanholt else 122145132Sanholt error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 123145132Sanholt s[i], l[i], ms->sectorsize, 124145132Sanholt "%ss%d", gp->name, i + 1); 125145132Sanholt if (error) 126145132Sanholt return (error); 127145132Sanholt } 128145132Sanholt 129145132Sanholt for (i = 0; i < NDOSPART; i++) { 130145132Sanholt ms->type[i] = (dp[i].dp_sid << 8) | dp[i].dp_mid; 131145132Sanholt g_slice_config(gp, i, G_SLICE_CONFIG_SET, s[i], l[i], 132145132Sanholt ms->sectorsize, "%ss%d", gp->name, i + 1); 133145132Sanholt } 134145132Sanholt 135145132Sanholt bcopy(sec, ms->sec, sizeof (ms->sec)); 136145132Sanholt 137145132Sanholt return (0); 138145132Sanholt} 139145132Sanholt 140145132Sanholtstatic int 141145132Sanholtg_pc98_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td) 142182080Srnoland{ 143145132Sanholt struct g_geom *gp; 144145132Sanholt struct g_pc98_softc *ms; 145145132Sanholt struct g_slicer *gsp; 146145132Sanholt struct g_consumer *cp; 147145132Sanholt int error; 148145132Sanholt 149145132Sanholt gp = pp->geom; 150145132Sanholt gsp = gp->softc; 151145132Sanholt ms = gsp->softc; 152145132Sanholt 153145132Sanholt switch(cmd) { 154145132Sanholt case DIOCSPC98: { 155145132Sanholt DROP_GIANT(); 156145132Sanholt g_topology_lock(); 157145132Sanholt /* Validate and modify our slicer instance to match. */ 158145132Sanholt error = g_pc98_modify(gp, ms, data); 159145132Sanholt cp = LIST_FIRST(&gp->consumer); 160145132Sanholt error = g_write_data(cp, 0, data, 8192); 161145132Sanholt g_topology_unlock(); 162145132Sanholt PICKUP_GIANT(); 163145132Sanholt return(error); 164182080Srnoland } 165145132Sanholt default: 166145132Sanholt return (ENOIOCTL); 167145132Sanholt } 168145132Sanholt} 169145132Sanholt 170152909Sanholtstatic int 171145132Sanholtg_pc98_start(struct bio *bp) 172145132Sanholt{ 173145132Sanholt struct g_provider *pp; 174145132Sanholt struct g_geom *gp; 175145132Sanholt struct g_pc98_softc *mp; 176145132Sanholt struct g_slicer *gsp; 177145132Sanholt int idx; 178145132Sanholt 179145132Sanholt pp = bp->bio_to; 180145132Sanholt idx = pp->index; 181145132Sanholt gp = pp->geom; 182145132Sanholt gsp = gp->softc; 183145132Sanholt mp = gsp->softc; 184145132Sanholt if (bp->bio_cmd == BIO_GETATTR) { 185145132Sanholt if (g_handleattr_int(bp, "PC98::type", mp->type[idx])) 186145132Sanholt return (1); 187145132Sanholt if (g_handleattr_off_t(bp, "PC98::offset", 188145132Sanholt gsp->slices[idx].offset)) 189145132Sanholt return (1); 190145132Sanholt } 191145132Sanholt 192145132Sanholt return (0); 193145132Sanholt} 194145132Sanholt 195145132Sanholtstatic void 196145132Sanholtg_pc98_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 197145132Sanholt struct g_consumer *cp __unused, struct g_provider *pp) 198145132Sanholt{ 199145132Sanholt struct g_pc98_softc *mp; 200145132Sanholt struct g_slicer *gsp; 201145132Sanholt struct pc98_partition dp; 202145132Sanholt char sname[17]; 203145132Sanholt 204145132Sanholt gsp = gp->softc; 205145132Sanholt mp = gsp->softc; 206145132Sanholt g_slice_dumpconf(sb, indent, gp, cp, pp); 207145132Sanholt if (pp != NULL) { 208145132Sanholt pc98_partition_dec( 209182080Srnoland mp->sec + 512 + 210145132Sanholt pp->index * sizeof(struct pc98_partition), &dp); 211145132Sanholt strncpy(sname, dp.dp_name, 16); 212182080Srnoland sname[16] = '\0'; 213182080Srnoland if (indent == NULL) { 214145132Sanholt sbuf_printf(sb, " ty %d", mp->type[pp->index]); 215145132Sanholt sbuf_printf(sb, " sn %s", sname); 216145132Sanholt } else { 217145132Sanholt sbuf_printf(sb, "%s<type>%d</type>\n", indent, 218145132Sanholt mp->type[pp->index]); 219145132Sanholt sbuf_printf(sb, "%s<sname>%s</sname>\n", indent, 220145132Sanholt sname); 221145132Sanholt } 222145132Sanholt } 223145132Sanholt} 224145132Sanholt 225145132Sanholtstatic struct g_geom * 226145132Sanholtg_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) 227145132Sanholt{ 228145132Sanholt struct g_geom *gp; 229145132Sanholt struct g_consumer *cp; 230145132Sanholt int error; 231145132Sanholt struct g_pc98_softc *ms; 232145132Sanholt u_int fwsectors, fwheads, sectorsize; 233145132Sanholt u_char *buf; 234145132Sanholt 235145132Sanholt g_trace(G_T_TOPOLOGY, "g_pc98_taste(%s,%s)", mp->name, pp->name); 236145132Sanholt g_topology_assert(); 237145132Sanholt if (flags == G_TF_NORMAL && 238145132Sanholt !strcmp(pp->geom->class->name, PC98_CLASS_NAME)) 239145132Sanholt return (NULL); 240145132Sanholt gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_pc98_start); 241145132Sanholt if (gp == NULL) 242182080Srnoland return (NULL); 243145132Sanholt g_topology_unlock(); 244145132Sanholt do { 245145132Sanholt if (gp->rank != 2 && flags == G_TF_NORMAL) 246145132Sanholt break; 247145132Sanholt error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 248145132Sanholt if (error || fwsectors == 0) { 249145132Sanholt fwsectors = 17; 250145132Sanholt if (bootverbose) 251145132Sanholt printf("g_pc98_taste: guessing %d sectors\n", 252145132Sanholt fwsectors); 253145132Sanholt } 254145132Sanholt error = g_getattr("GEOM::fwheads", cp, &fwheads); 255145132Sanholt if (error || fwheads == 0) { 256145132Sanholt fwheads = 8; 257145132Sanholt if (bootverbose) 258145132Sanholt printf("g_pc98_taste: guessing %d heads\n", 259145132Sanholt fwheads); 260145132Sanholt } 261145132Sanholt sectorsize = cp->provider->sectorsize; 262145132Sanholt if (sectorsize % 512 != 0) 263145132Sanholt break; 264145132Sanholt if (!strncmp(gp->name, "ad", 2)) { 265145132Sanholt u_int total_secs = cp->provider->mediasize/sectorsize; 266145132Sanholt 267145132Sanholt if (total_secs < 17*8*65535) { 268145132Sanholt fwsectors = 17; 269145132Sanholt fwheads = 8; 270145132Sanholt } 271145132Sanholt else if (total_secs < 63*16*65535) { 272145132Sanholt if (fwsectors > 63) 273145132Sanholt fwsectors = 63; 274145132Sanholt if (fwheads > 16) 275182080Srnoland fwheads = 16; 276145132Sanholt } 277145132Sanholt else if (total_secs < 255*16*65535) { 278145132Sanholt fwsectors = 255; 279145132Sanholt if (fwheads > 16) 280145132Sanholt fwheads = 16; 281145132Sanholt } 282145132Sanholt else { 283145132Sanholt fwsectors = 255; 284145132Sanholt fwheads = 255; 285145132Sanholt } 286145132Sanholt } 287145132Sanholt buf = g_read_data(cp, 0, 8192, &error); 288145132Sanholt if (buf == NULL || error != 0) 289145132Sanholt break; 290145132Sanholt ms->fwsectors = fwsectors; 291145132Sanholt ms->fwheads = fwheads; 292145132Sanholt ms->sectorsize = sectorsize; 293145132Sanholt g_topology_lock(); 294145132Sanholt g_pc98_modify(gp, ms, buf); 295145132Sanholt g_topology_unlock(); 296145132Sanholt g_free(buf); 297145132Sanholt break; 298145132Sanholt } while (0); 299145132Sanholt g_topology_lock(); 300145132Sanholt g_access(cp, -1, 0, 0); 301145132Sanholt if (LIST_EMPTY(&gp->provider)) { 302145132Sanholt g_slice_spoiled(cp); 303145132Sanholt return (NULL); 304145132Sanholt } 305157617Sanholt return (gp); 306145132Sanholt} 307182080Srnoland 308145132Sanholtstatic struct g_class g_pc98_class = { 309145132Sanholt .name = PC98_CLASS_NAME, 310145132Sanholt .version = G_VERSION, 311145132Sanholt .taste = g_pc98_taste, 312145132Sanholt .dumpconf = g_pc98_dumpconf, 313145132Sanholt .ioctl = g_pc98_ioctl, 314145132Sanholt}; 315145132Sanholt 316145132SanholtDECLARE_GEOM_CLASS(g_pc98_class, g_pc98); 317145132Sanholt