geom_pc98.c revision 113390
123228Swosch/*- 223228Swosch * Copyright (c) 2002 Poul-Henning Kamp 323228Swosch * Copyright (c) 2002 Networks Associates Technology, Inc. 423228Swosch * All rights reserved. 523228Swosch * 623228Swosch * This software was developed for the FreeBSD Project by Poul-Henning Kamp 723228Swosch * and NAI Labs, the Security Research Division of Network Associates, Inc. 823228Swosch * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 923228Swosch * DARPA CHATS research program. 1023228Swosch * 1123228Swosch * Redistribution and use in source and binary forms, with or without 1223228Swosch * modification, are permitted provided that the following conditions 1323228Swosch * are met: 1423228Swosch * 1. Redistributions of source code must retain the above copyright 1523228Swosch * notice, this list of conditions and the following disclaimer. 1623228Swosch * 2. Redistributions in binary form must reproduce the above copyright 1723228Swosch * notice, this list of conditions and the following disclaimer in the 1823228Swosch * documentation and/or other materials provided with the distribution. 1923228Swosch * 2023228Swosch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2123228Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2223228Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2323228Swosch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2423228Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2523228Swosch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2623228Swosch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2723228Swosch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2823228Swosch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2923228Swosch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3023228Swosch * SUCH DAMAGE. 3123228Swosch * 3223228Swosch * $FreeBSD: head/sys/geom/geom_pc98.c 113390 2003-04-12 08:41:26Z phk $ 3323228Swosch */ 3423228Swosch 3523228Swosch#include <sys/param.h> 3623228Swosch#include <sys/endian.h> 3723228Swosch#ifndef _KERNEL 3823228Swosch#include <signal.h> 3923228Swosch#include <stdio.h> 4023228Swosch#include <stdlib.h> 4123228Swosch#include <string.h> 4223228Swosch#include <errno.h> 4323228Swosch#else 4423228Swosch#include <sys/systm.h> 4523228Swosch#include <sys/kernel.h> 4623228Swosch#include <sys/malloc.h> 4723228Swosch#include <sys/bio.h> 4823228Swosch#include <sys/lock.h> 4923228Swosch#include <sys/mutex.h> 5023228Swosch#endif 5123228Swosch 5223228Swosch#include <sys/diskpc98.h> 5323228Swosch#include <geom/geom.h> 5423228Swosch#include <geom/geom_slice.h> 5523228Swosch 5623228Swosch#define PC98_CLASS_NAME "PC98" 5723228Swosch 5823228Swoschstatic void 5923228Swoschg_dec_pc98_partition(u_char *ptr, struct pc98_partition *d) 6023228Swosch{ 6123228Swosch u_int u; 6223228Swosch 6323228Swosch d->dp_mid = ptr[0]; 6423228Swosch d->dp_sid = ptr[1]; 6523228Swosch d->dp_dum1 = ptr[2]; 6623228Swosch d->dp_dum2 = ptr[3]; 6723228Swosch d->dp_ipl_sct = ptr[4]; 6823228Swosch d->dp_ipl_head = ptr[5]; 6923228Swosch d->dp_ipl_cyl = le16dec(ptr + 6); 7023228Swosch d->dp_ssect = ptr[8]; 7123228Swosch d->dp_shd = ptr[9]; 7223228Swosch d->dp_scyl = le16dec(ptr + 10); 7323228Swosch d->dp_esect = ptr[12]; 7423228Swosch d->dp_ehd = ptr[13]; 7523228Swosch d->dp_ecyl = le16dec(ptr + 14); 7623228Swosch for (u = 0; u < sizeof(d->dp_name); u++) 7723228Swosch d->dp_name[u] = ptr[16 + u]; 7823228Swosch} 7923228Swosch 8023228Swoschstruct g_pc98_softc { 8123228Swosch u_int fwsectors, fwheads, sectorsize; 8223228Swosch int type[NDOSPART]; 8323228Swosch u_char sec[8192]; 8423228Swosch}; 8523228Swosch 8623228Swoschstatic void 8723228Swoschg_pc98_print(int i, struct pc98_partition *dp) 8823228Swosch{ 8923228Swosch char sname[17]; 9023228Swosch 9123228Swosch strncpy(sname, dp->dp_name, 16); 9223228Swosch sname[16] = '\0'; 9323228Swosch 9423228Swosch g_hexdump(dp, sizeof(dp[0])); 9523228Swosch printf("[%d] mid:%d(0x%x) sid:%d(0x%x)", 9623228Swosch i, dp->dp_mid, dp->dp_mid, dp->dp_sid, dp->dp_sid); 9723228Swosch printf(" s:%d/%d/%d", dp->dp_scyl, dp->dp_shd, dp->dp_ssect); 9823228Swosch printf(" e:%d/%d/%d", dp->dp_ecyl, dp->dp_ehd, dp->dp_esect); 9923228Swosch printf(" sname:%s\n", sname); 10023228Swosch} 10123228Swosch 10223228Swoschstatic int 10323228Swoschg_pc98_modify(struct g_geom *gp, struct g_pc98_softc *ms, u_char *sec) 10423228Swosch{ 10523228Swosch int i, error; 10623228Swosch off_t s[NDOSPART], l[NDOSPART]; 10723228Swosch struct pc98_partition dp[NDOSPART]; 10823228Swosch 10923228Swosch g_topology_assert(); 11023228Swosch 11123228Swosch if (sec[0x1fe] != 0x55 || sec[0x1ff] != 0xaa) 11223228Swosch return (EBUSY); 11323228Swosch 11423228Swosch#if 0 11523228Swosch /* 11623228Swosch * XXX: Some sources indicate this is a magic sequence, but appearantly 11723228Swosch * XXX: it is not universal. Documentation would be wonderful to have. 11823228Swosch */ 11923228Swosch if (sec[4] != 'I' || sec[5] != 'P' || sec[6] != 'L' || sec[7] != '1') 12023228Swosch return (EBUSY); 12123228Swosch#endif 12223228Swosch 12323228Swosch for (i = 0; i < NDOSPART; i++) 12423228Swosch g_dec_pc98_partition( 12523228Swosch sec + 512 + i * sizeof(struct pc98_partition), &dp[i]); 12623228Swosch 12723228Swosch for (i = 0; i < NDOSPART; i++) { 12823228Swosch /* If start and end are identical it's bogus */ 12923228Swosch if (dp[i].dp_ssect == dp[i].dp_esect && 13023228Swosch dp[i].dp_shd == dp[i].dp_ehd && 13123228Swosch dp[i].dp_scyl == dp[i].dp_ecyl) 13223228Swosch s[i] = l[i] = 0; 13323228Swosch else if (dp[i].dp_ecyl == 0) 13423228Swosch s[i] = l[i] = 0; 13523228Swosch else { 13623228Swosch s[i] = (off_t)dp[i].dp_scyl * 13723228Swosch ms->fwsectors * ms->fwheads * ms->sectorsize; 13823228Swosch l[i] = (off_t)(dp[i].dp_ecyl - dp[i].dp_scyl + 1) * 13923228Swosch ms->fwsectors * ms->fwheads * ms->sectorsize; 14023228Swosch } 14123228Swosch if (bootverbose) { 14223228Swosch printf("PC98 Slice %d on %s:\n", i + 1, gp->name); 14323228Swosch g_pc98_print(i, dp + i); 14423228Swosch } 14523228Swosch if (s[i] < 0 || l[i] < 0) 14623228Swosch error = EBUSY; 14723228Swosch else 14823228Swosch error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 14923228Swosch s[i], l[i], ms->sectorsize, 15023228Swosch "%ss%d", gp->name, i + 1); 15123228Swosch if (error) 15223228Swosch return (error); 15323228Swosch } 15423228Swosch 15523228Swosch for (i = 0; i < NDOSPART; i++) { 15623228Swosch ms->type[i] = (dp[i].dp_sid << 8) | dp[i].dp_mid; 15723228Swosch g_slice_config(gp, i, G_SLICE_CONFIG_SET, s[i], l[i], 15823228Swosch ms->sectorsize, "%ss%d", gp->name, i + 1); 15923228Swosch } 16023228Swosch 16123228Swosch bcopy(sec, ms->sec, sizeof (ms->sec)); 16223228Swosch 16323228Swosch return (0); 16423228Swosch} 16523228Swosch 16623228Swoschstatic void 16723228Swoschg_pc98_ioctl(void *arg, int flag) 16823228Swosch{ 16923228Swosch struct bio *bp; 17023228Swosch struct g_geom *gp; 17123228Swosch struct g_slicer *gsp; 17223228Swosch struct g_pc98_softc *ms; 17323228Swosch struct g_ioctl *gio; 17423228Swosch struct g_consumer *cp; 175 u_char *sec; 176 int error; 177 178 bp = arg; 179 if (flag == EV_CANCEL) { 180 g_io_deliver(bp, ENXIO); 181 return; 182 } 183 gp = bp->bio_to->geom; 184 gsp = gp->softc; 185 ms = gsp->softc; 186 gio = (struct g_ioctl *)bp->bio_data; 187 188 /* The disklabel to set is the ioctl argument. */ 189 sec = gio->data; 190 191 error = g_pc98_modify(gp, ms, sec); 192 if (error) { 193 g_io_deliver(bp, error); 194 return; 195 } 196 cp = LIST_FIRST(&gp->consumer); 197 error = g_write_data(cp, 0, sec, 8192); 198 g_io_deliver(bp, error); 199} 200 201static int 202g_pc98_start(struct bio *bp) 203{ 204 struct g_provider *pp; 205 struct g_geom *gp; 206 struct g_pc98_softc *mp; 207 struct g_slicer *gsp; 208 struct g_ioctl *gio; 209 int idx, error; 210 211 pp = bp->bio_to; 212 idx = pp->index; 213 gp = pp->geom; 214 gsp = gp->softc; 215 mp = gsp->softc; 216 if (bp->bio_cmd == BIO_GETATTR) { 217 if (g_handleattr_int(bp, "PC98::type", mp->type[idx])) 218 return (1); 219 if (g_handleattr_off_t(bp, "PC98::offset", 220 gsp->slices[idx].offset)) 221 return (1); 222 } 223 224 /* We only handle ioctl(2) requests of the right format. */ 225 if (strcmp(bp->bio_attribute, "GEOM::ioctl")) 226 return (0); 227 else if (bp->bio_length != sizeof(*gio)) 228 return (0); 229 /* Get hold of the ioctl parameters. */ 230 gio = (struct g_ioctl *)bp->bio_data; 231 232 switch (gio->cmd) { 233 case DIOCGPC98: 234 /* Return a copy of the disklabel to userland. */ 235 bcopy(mp->sec, gio->data, 8192); 236 g_io_deliver(bp, 0); 237 return (1); 238 case DIOCSPC98: 239 /* 240 * These we cannot do without the topology lock and some 241 * some I/O requests. Ask the event-handler to schedule 242 * us in a less restricted environment. 243 */ 244 error = g_call_me(g_pc98_ioctl, bp, gp, NULL); 245 if (error) 246 g_io_deliver(bp, error); 247 /* 248 * We must return non-zero to indicate that we will deal 249 * with this bio, even though we have not done so yet. 250 */ 251 return (1); 252 default: 253 return (0); 254 } 255 256 return (0); 257} 258 259static void 260g_pc98_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 261 struct g_consumer *cp __unused, struct g_provider *pp) 262{ 263 struct g_pc98_softc *mp; 264 struct g_slicer *gsp; 265 struct pc98_partition dp; 266 char sname[17]; 267 268 gsp = gp->softc; 269 mp = gsp->softc; 270 g_slice_dumpconf(sb, indent, gp, cp, pp); 271 if (pp != NULL) { 272 g_dec_pc98_partition( 273 mp->sec + 512 + 274 pp->index * sizeof(struct pc98_partition), &dp); 275 strncpy(sname, dp.dp_name, 16); 276 sname[16] = '\0'; 277 if (indent == NULL) { 278 sbuf_printf(sb, " ty %d", mp->type[pp->index]); 279 sbuf_printf(sb, " sn %s", sname); 280 } else { 281 sbuf_printf(sb, "%s<type>%d</type>\n", indent, 282 mp->type[pp->index]); 283 sbuf_printf(sb, "%s<sname>%s</sname>\n", indent, 284 sname); 285 } 286 } 287} 288 289static struct g_geom * 290g_pc98_taste(struct g_class *mp, struct g_provider *pp, int flags) 291{ 292 struct g_geom *gp; 293 struct g_consumer *cp; 294 int error; 295 struct g_pc98_softc *ms; 296 struct g_slicer *gsp; 297 u_int fwsectors, fwheads, sectorsize; 298 u_char *buf; 299 300 g_trace(G_T_TOPOLOGY, "g_pc98_taste(%s,%s)", mp->name, pp->name); 301 g_topology_assert(); 302 if (flags == G_TF_NORMAL && 303 !strcmp(pp->geom->class->name, PC98_CLASS_NAME)) 304 return (NULL); 305 gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_pc98_start); 306 if (gp == NULL) 307 return (NULL); 308 gsp = gp->softc; 309 g_topology_unlock(); 310 gp->dumpconf = g_pc98_dumpconf; 311 do { 312 if (gp->rank != 2 && flags == G_TF_NORMAL) 313 break; 314 error = g_getattr("GEOM::fwsectors", cp, &fwsectors); 315 if (error || fwsectors == 0) { 316 fwsectors = 17; 317 if (bootverbose) 318 printf("g_pc98_taste: guessing %d sectors\n", 319 fwsectors); 320 } 321 error = g_getattr("GEOM::fwheads", cp, &fwheads); 322 if (error || fwheads == 0) { 323 fwheads = 8; 324 if (bootverbose) 325 printf("g_pc98_taste: guessing %d heads\n", 326 fwheads); 327 } 328 sectorsize = cp->provider->sectorsize; 329 if (sectorsize < 512) 330 break; 331 buf = g_read_data(cp, 0, 8192, &error); 332 if (buf == NULL || error != 0) 333 break; 334 ms->fwsectors = fwsectors; 335 ms->fwheads = fwheads; 336 ms->sectorsize = sectorsize; 337 g_topology_lock(); 338 g_pc98_modify(gp, ms, buf); 339 g_topology_unlock(); 340 g_free(buf); 341 break; 342 } while (0); 343 g_topology_lock(); 344 g_access_rel(cp, -1, 0, 0); 345 if (LIST_EMPTY(&gp->provider)) { 346 g_std_spoiled(cp); 347 return (NULL); 348 } 349 return (gp); 350} 351 352static struct g_class g_pc98_class = { 353 .name = PC98_CLASS_NAME, 354 .taste = g_pc98_taste, 355 G_CLASS_INITIALIZER 356}; 357 358DECLARE_GEOM_CLASS(g_pc98_class, g_pc98); 359