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