1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/param.h> 30*0Sstevel@tonic-gate #include <sys/systm.h> 31*0Sstevel@tonic-gate #include <sys/kmem.h> 32*0Sstevel@tonic-gate #include <sys/user.h> 33*0Sstevel@tonic-gate #include <sys/proc.h> 34*0Sstevel@tonic-gate #include <sys/cred.h> 35*0Sstevel@tonic-gate #include <sys/disp.h> 36*0Sstevel@tonic-gate #include <sys/buf.h> 37*0Sstevel@tonic-gate #include <sys/vfs.h> 38*0Sstevel@tonic-gate #include <sys/vnode.h> 39*0Sstevel@tonic-gate #include <sys/fdio.h> 40*0Sstevel@tonic-gate #include <sys/file.h> 41*0Sstevel@tonic-gate #include <sys/uio.h> 42*0Sstevel@tonic-gate #include <sys/conf.h> 43*0Sstevel@tonic-gate #undef NFSCLIENT 44*0Sstevel@tonic-gate #include <sys/statvfs.h> 45*0Sstevel@tonic-gate #include <sys/mount.h> 46*0Sstevel@tonic-gate #include <sys/pathname.h> 47*0Sstevel@tonic-gate #include <sys/cmn_err.h> 48*0Sstevel@tonic-gate #include <sys/debug.h> 49*0Sstevel@tonic-gate #include <sys/sysmacros.h> 50*0Sstevel@tonic-gate #include <sys/conf.h> 51*0Sstevel@tonic-gate #include <sys/mkdev.h> 52*0Sstevel@tonic-gate #include <sys/swap.h> 53*0Sstevel@tonic-gate #include <sys/sunddi.h> 54*0Sstevel@tonic-gate #include <sys/sunldi.h> 55*0Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 56*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 57*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 58*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 59*0Sstevel@tonic-gate #include <sys/fs/pc_node.h> 60*0Sstevel@tonic-gate #include <fs/fs_subr.h> 61*0Sstevel@tonic-gate #include <sys/modctl.h> 62*0Sstevel@tonic-gate #include <sys/vol.h> 63*0Sstevel@tonic-gate #include <sys/dkio.h> 64*0Sstevel@tonic-gate #include <sys/open.h> 65*0Sstevel@tonic-gate #include <sys/mntent.h> 66*0Sstevel@tonic-gate #include <sys/policy.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * The majority of PC media use a 512 sector size, but 70*0Sstevel@tonic-gate * occasionally you will run across a 1k sector size. 71*0Sstevel@tonic-gate * For media with a 1k sector size, fd_strategy() requires 72*0Sstevel@tonic-gate * the I/O size to be a 1k multiple; so when the sector size 73*0Sstevel@tonic-gate * is not yet known, always read 1k. 74*0Sstevel@tonic-gate */ 75*0Sstevel@tonic-gate #define PC_SAFESECSIZE (PC_SECSIZE * 2) 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate static int pcfs_psuedo_floppy(dev_t); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate static int pcfsinit(int, char *); 80*0Sstevel@tonic-gate static int pcfs_mount(struct vfs *, struct vnode *, struct mounta *, 81*0Sstevel@tonic-gate struct cred *); 82*0Sstevel@tonic-gate static int pcfs_unmount(struct vfs *, int, struct cred *); 83*0Sstevel@tonic-gate static int pcfs_root(struct vfs *, struct vnode **); 84*0Sstevel@tonic-gate static int pcfs_statvfs(struct vfs *, struct statvfs64 *); 85*0Sstevel@tonic-gate static int pc_syncfsnodes(struct pcfs *); 86*0Sstevel@tonic-gate static int pcfs_sync(struct vfs *, short, struct cred *); 87*0Sstevel@tonic-gate static int pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate static int pc_getfattype(struct vnode *, int, daddr_t *, int *); 90*0Sstevel@tonic-gate static int pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, 91*0Sstevel@tonic-gate size_t fatsize); 92*0Sstevel@tonic-gate static int pc_writefat(struct pcfs *fsp, daddr_t start); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * pcfs mount options table 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static char *nohidden_cancel[] = {MNTOPT_PCFS_HIDDEN, NULL}; 99*0Sstevel@tonic-gate static char *hidden_cancel[] = {MNTOPT_PCFS_NOHIDDEN, NULL}; 100*0Sstevel@tonic-gate static char *nofoldcase_cancel[] = {MNTOPT_PCFS_FOLDCASE, NULL}; 101*0Sstevel@tonic-gate static char *foldcase_cancel[] = {MNTOPT_PCFS_NOFOLDCASE, NULL}; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate static mntopt_t mntopts[] = { 104*0Sstevel@tonic-gate /* 105*0Sstevel@tonic-gate * option name cancel option default arg flags 106*0Sstevel@tonic-gate * opt data 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate { MNTOPT_PCFS_NOHIDDEN, nohidden_cancel, NULL, MO_DEFAULT, 109*0Sstevel@tonic-gate NULL }, 110*0Sstevel@tonic-gate { MNTOPT_PCFS_HIDDEN, hidden_cancel, NULL, 0, 111*0Sstevel@tonic-gate NULL }, 112*0Sstevel@tonic-gate { MNTOPT_PCFS_NOFOLDCASE, nofoldcase_cancel, NULL, MO_DEFAULT, 113*0Sstevel@tonic-gate NULL }, 114*0Sstevel@tonic-gate { MNTOPT_PCFS_FOLDCASE, foldcase_cancel, NULL, 0, 115*0Sstevel@tonic-gate NULL } 116*0Sstevel@tonic-gate }; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate static mntopts_t pcfs_mntopts = { 119*0Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t), 120*0Sstevel@tonic-gate mntopts 121*0Sstevel@tonic-gate }; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate int pcfsdebuglevel = 0; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * pcfslock: protects the list of mounted pc filesystems "pc_mounttab. 127*0Sstevel@tonic-gate * pcfs_lock: (inside per filesystem structure "pcfs") 128*0Sstevel@tonic-gate * per filesystem lock. Most of the vfsops and vnodeops are 129*0Sstevel@tonic-gate * protected by this lock. 130*0Sstevel@tonic-gate * pcnodes_lock: protects the pcnode hash table "pcdhead", "pcfhead". 131*0Sstevel@tonic-gate * 132*0Sstevel@tonic-gate * Lock hierarchy: pcfslock > pcfs_lock > pcnodes_lock 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate kmutex_t pcfslock; 135*0Sstevel@tonic-gate krwlock_t pcnodes_lock; /* protect the pcnode hash table "pcdhead", "pcfhead" */ 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate static int pcfstype; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate static vfsdef_t vfw = { 140*0Sstevel@tonic-gate VFSDEF_VERSION, 141*0Sstevel@tonic-gate "pcfs", 142*0Sstevel@tonic-gate pcfsinit, 143*0Sstevel@tonic-gate VSW_HASPROTO|VSW_CANREMOUNT, 144*0Sstevel@tonic-gate &pcfs_mntopts 145*0Sstevel@tonic-gate }; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate extern struct mod_ops mod_fsops; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate static struct modlfs modlfs = { 150*0Sstevel@tonic-gate &mod_fsops, 151*0Sstevel@tonic-gate "filesystem for PC", 152*0Sstevel@tonic-gate &vfw 153*0Sstevel@tonic-gate }; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 156*0Sstevel@tonic-gate MODREV_1, 157*0Sstevel@tonic-gate &modlfs, 158*0Sstevel@tonic-gate NULL 159*0Sstevel@tonic-gate }; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate int 162*0Sstevel@tonic-gate _init(void) 163*0Sstevel@tonic-gate { 164*0Sstevel@tonic-gate int error; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate #if !defined(lint) 167*0Sstevel@tonic-gate /* make sure the on-disk structures are sane */ 168*0Sstevel@tonic-gate ASSERT(sizeof (struct pcdir) == 32); 169*0Sstevel@tonic-gate ASSERT(sizeof (struct pcdir_lfn) == 32); 170*0Sstevel@tonic-gate #endif 171*0Sstevel@tonic-gate mutex_init(&pcfslock, NULL, MUTEX_DEFAULT, NULL); 172*0Sstevel@tonic-gate rw_init(&pcnodes_lock, NULL, RW_DEFAULT, NULL); 173*0Sstevel@tonic-gate error = mod_install(&modlinkage); 174*0Sstevel@tonic-gate if (error) { 175*0Sstevel@tonic-gate mutex_destroy(&pcfslock); 176*0Sstevel@tonic-gate rw_destroy(&pcnodes_lock); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate return (error); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate int 182*0Sstevel@tonic-gate _fini(void) 183*0Sstevel@tonic-gate { 184*0Sstevel@tonic-gate int error; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate error = mod_remove(&modlinkage); 187*0Sstevel@tonic-gate if (error) 188*0Sstevel@tonic-gate return (error); 189*0Sstevel@tonic-gate mutex_destroy(&pcfslock); 190*0Sstevel@tonic-gate rw_destroy(&pcnodes_lock); 191*0Sstevel@tonic-gate /* 192*0Sstevel@tonic-gate * Tear down the operations vectors 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(pcfstype); 195*0Sstevel@tonic-gate vn_freevnodeops(pcfs_fvnodeops); 196*0Sstevel@tonic-gate vn_freevnodeops(pcfs_dvnodeops); 197*0Sstevel@tonic-gate return (0); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate int 201*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* ARGSUSED1 */ 207*0Sstevel@tonic-gate static int 208*0Sstevel@tonic-gate pcfsinit(int fstype, char *name) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate static const fs_operation_def_t pcfs_vfsops_template[] = { 211*0Sstevel@tonic-gate VFSNAME_MOUNT, pcfs_mount, 212*0Sstevel@tonic-gate VFSNAME_UNMOUNT, pcfs_unmount, 213*0Sstevel@tonic-gate VFSNAME_ROOT, pcfs_root, 214*0Sstevel@tonic-gate VFSNAME_STATVFS, pcfs_statvfs, 215*0Sstevel@tonic-gate VFSNAME_SYNC, (fs_generic_func_p) pcfs_sync, 216*0Sstevel@tonic-gate VFSNAME_VGET, pcfs_vget, 217*0Sstevel@tonic-gate NULL, NULL 218*0Sstevel@tonic-gate }; 219*0Sstevel@tonic-gate int error; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate error = vfs_setfsops(fstype, pcfs_vfsops_template, NULL); 222*0Sstevel@tonic-gate if (error != 0) { 223*0Sstevel@tonic-gate cmn_err(CE_WARN, "pcfsinit: bad vfs ops template"); 224*0Sstevel@tonic-gate return (error); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate error = vn_make_ops("pcfs", pcfs_fvnodeops_template, &pcfs_fvnodeops); 228*0Sstevel@tonic-gate if (error != 0) { 229*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 230*0Sstevel@tonic-gate cmn_err(CE_WARN, "pcfsinit: bad file vnode ops template"); 231*0Sstevel@tonic-gate return (error); 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate error = vn_make_ops("pcfsd", pcfs_dvnodeops_template, &pcfs_dvnodeops); 235*0Sstevel@tonic-gate if (error != 0) { 236*0Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 237*0Sstevel@tonic-gate vn_freevnodeops(pcfs_fvnodeops); 238*0Sstevel@tonic-gate cmn_err(CE_WARN, "pcfsinit: bad dir vnode ops template"); 239*0Sstevel@tonic-gate return (error); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate pcfstype = fstype; 243*0Sstevel@tonic-gate (void) pc_init(); 244*0Sstevel@tonic-gate return (0); 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate static struct pcfs *pc_mounttab = NULL; 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate extern struct pcfs_args pc_tz; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * Define some special logical drives we use internal to this file. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate #define BOOT_PARTITION_DRIVE 99 255*0Sstevel@tonic-gate #define PRIMARY_DOS_DRIVE 1 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * pc_mount system call 259*0Sstevel@tonic-gate */ 260*0Sstevel@tonic-gate static int 261*0Sstevel@tonic-gate pcfs_mount( 262*0Sstevel@tonic-gate struct vfs *vfsp, 263*0Sstevel@tonic-gate struct vnode *mvp, 264*0Sstevel@tonic-gate struct mounta *uap, 265*0Sstevel@tonic-gate struct cred *cr) 266*0Sstevel@tonic-gate { 267*0Sstevel@tonic-gate struct pcfs *fsp; 268*0Sstevel@tonic-gate struct vnode *bvp; 269*0Sstevel@tonic-gate struct vnode *devvp; 270*0Sstevel@tonic-gate struct pathname special; 271*0Sstevel@tonic-gate daddr_t dosstart; 272*0Sstevel@tonic-gate dev_t pseudodev; 273*0Sstevel@tonic-gate dev_t xdev; 274*0Sstevel@tonic-gate char *spnp; 275*0Sstevel@tonic-gate char *data = uap->dataptr; 276*0Sstevel@tonic-gate int datalen = uap->datalen; 277*0Sstevel@tonic-gate int dos_ldrive = 0; 278*0Sstevel@tonic-gate int error; 279*0Sstevel@tonic-gate int fattype; 280*0Sstevel@tonic-gate int spnlen; 281*0Sstevel@tonic-gate int wantbootpart = 0; 282*0Sstevel@tonic-gate struct vioc_info info; 283*0Sstevel@tonic-gate int rval; /* set but not used */ 284*0Sstevel@tonic-gate minor_t minor; 285*0Sstevel@tonic-gate int oflag, aflag; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 288*0Sstevel@tonic-gate return (error); 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate PC_DPRINTF0(4, "pcfs_mount\n"); 291*0Sstevel@tonic-gate if (mvp->v_type != VDIR) { 292*0Sstevel@tonic-gate return (ENOTDIR); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 295*0Sstevel@tonic-gate if ((uap->flags & MS_REMOUNT) == 0 && 296*0Sstevel@tonic-gate (uap->flags & MS_OVERLAY) == 0 && 297*0Sstevel@tonic-gate (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 298*0Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 299*0Sstevel@tonic-gate return (EBUSY); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * The caller is responsible for making sure to always 305*0Sstevel@tonic-gate * pass in sizeof(struct pcfs_args) (or the old one). 306*0Sstevel@tonic-gate * Doing this is the only way to know an EINVAL return 307*0Sstevel@tonic-gate * from mount(2) is due to the "not a DOS filesystem" 308*0Sstevel@tonic-gate * EINVAL that pc_verify/pc_getfattype could return. 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate if ((datalen != sizeof (struct pcfs_args)) && 311*0Sstevel@tonic-gate (datalen != sizeof (struct old_pcfs_args))) { 312*0Sstevel@tonic-gate return (EINVAL); 313*0Sstevel@tonic-gate } else { 314*0Sstevel@tonic-gate struct pcfs_args tmp_tz; 315*0Sstevel@tonic-gate int hidden = 0; 316*0Sstevel@tonic-gate int foldcase = 0; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate tmp_tz.flags = 0; 319*0Sstevel@tonic-gate if (copyin(data, &tmp_tz, datalen)) { 320*0Sstevel@tonic-gate return (EFAULT); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate if (datalen == sizeof (struct pcfs_args)) { 323*0Sstevel@tonic-gate hidden = tmp_tz.flags & PCFS_MNT_HIDDEN; 324*0Sstevel@tonic-gate foldcase = tmp_tz.flags & PCFS_MNT_FOLDCASE; 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate if (hidden) 328*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_PCFS_HIDDEN, NULL, 0); 329*0Sstevel@tonic-gate if (foldcase) 330*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_PCFS_FOLDCASE, NULL, 0); 331*0Sstevel@tonic-gate /* 332*0Sstevel@tonic-gate * more than one pc filesystem can be mounted on x86 333*0Sstevel@tonic-gate * so the pc_tz structure is now a critical region 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate mutex_enter(&pcfslock); 336*0Sstevel@tonic-gate if (pc_mounttab == NULL) 337*0Sstevel@tonic-gate bcopy(&tmp_tz, &pc_tz, sizeof (struct pcfs_args)); 338*0Sstevel@tonic-gate mutex_exit(&pcfslock); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * Resolve path name of special file being mounted. 342*0Sstevel@tonic-gate */ 343*0Sstevel@tonic-gate if (error = pn_get(uap->spec, UIO_USERSPACE, &special)) { 344*0Sstevel@tonic-gate return (error); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate if (error = 347*0Sstevel@tonic-gate lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) { 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * look for suffix to special 350*0Sstevel@tonic-gate * which indicates a request to mount the solaris boot 351*0Sstevel@tonic-gate * partition, or a DOS logical drive on the hard disk 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate spnlen = special.pn_pathlen; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate if (spnlen > 5) { 356*0Sstevel@tonic-gate spnp = special.pn_path + spnlen - 5; 357*0Sstevel@tonic-gate if (*spnp++ == ':' && *spnp++ == 'b' && 358*0Sstevel@tonic-gate *spnp++ == 'o' && *spnp++ == 'o' && 359*0Sstevel@tonic-gate *spnp++ == 't') { 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Looks as if they want to mount 362*0Sstevel@tonic-gate * the Solaris boot partition 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate wantbootpart = 1; 365*0Sstevel@tonic-gate dos_ldrive = BOOT_PARTITION_DRIVE; 366*0Sstevel@tonic-gate spnp = special.pn_path + spnlen - 5; 367*0Sstevel@tonic-gate *spnp = '\0'; 368*0Sstevel@tonic-gate error = lookupname(special.pn_path, 369*0Sstevel@tonic-gate UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate if (!wantbootpart) { 374*0Sstevel@tonic-gate spnp = special.pn_path + spnlen - 1; 375*0Sstevel@tonic-gate if (spnlen > 2 && *spnp >= 'c' && *spnp <= 'z') { 376*0Sstevel@tonic-gate spnlen--; 377*0Sstevel@tonic-gate dos_ldrive = *spnp-- - 'c' + 1; 378*0Sstevel@tonic-gate } else if (spnlen > 2 && *spnp >= '0' && *spnp <= '9') { 379*0Sstevel@tonic-gate spnlen--; 380*0Sstevel@tonic-gate dos_ldrive = *spnp-- - '0'; 381*0Sstevel@tonic-gate if (spnlen > 2 && *spnp >= '0' && 382*0Sstevel@tonic-gate *spnp <= '9') { 383*0Sstevel@tonic-gate spnlen--; 384*0Sstevel@tonic-gate dos_ldrive += 10 * (*spnp-- - '0'); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate if (spnlen > 1 && dos_ldrive && dos_ldrive <= 24 && 388*0Sstevel@tonic-gate *spnp == ':') { 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * remove suffix so that we have a real 391*0Sstevel@tonic-gate * device name 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate *spnp = '\0'; 394*0Sstevel@tonic-gate error = lookupname(special.pn_path, 395*0Sstevel@tonic-gate UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate if (error) { 399*0Sstevel@tonic-gate pn_free(&special); 400*0Sstevel@tonic-gate return (error); 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate pn_free(&special); 404*0Sstevel@tonic-gate if (bvp->v_type != VBLK) { 405*0Sstevel@tonic-gate VN_RELE(bvp); 406*0Sstevel@tonic-gate return (ENOTBLK); 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate xdev = bvp->v_rdev; 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * Verify caller's permission to open the device special file. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 413*0Sstevel@tonic-gate ((uap->flags & MS_RDONLY) != 0)) { 414*0Sstevel@tonic-gate oflag = FREAD; 415*0Sstevel@tonic-gate aflag = VREAD; 416*0Sstevel@tonic-gate } else { 417*0Sstevel@tonic-gate oflag = FREAD | FWRITE; 418*0Sstevel@tonic-gate aflag = VREAD | VWRITE; 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate if ((error = VOP_ACCESS(bvp, aflag, 0, cr)) != 0 || 421*0Sstevel@tonic-gate (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) { 422*0Sstevel@tonic-gate VN_RELE(bvp); 423*0Sstevel@tonic-gate return (error); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate VN_RELE(bvp); 427*0Sstevel@tonic-gate if (getmajor(xdev) >= devcnt) { 428*0Sstevel@tonic-gate return (ENXIO); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * Ensure that this device (or logical drive) isn't already mounted, 432*0Sstevel@tonic-gate * unless this is a REMOUNT request 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate if (dos_ldrive) { 435*0Sstevel@tonic-gate mutex_enter(&pcfslock); 436*0Sstevel@tonic-gate for (fsp = pc_mounttab; fsp; fsp = fsp->pcfs_nxt) 437*0Sstevel@tonic-gate if (fsp->pcfs_xdev == xdev && 438*0Sstevel@tonic-gate fsp->pcfs_ldrv == dos_ldrive) { 439*0Sstevel@tonic-gate mutex_exit(&pcfslock); 440*0Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 441*0Sstevel@tonic-gate return (0); 442*0Sstevel@tonic-gate } else { 443*0Sstevel@tonic-gate return (EBUSY); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * Assign a unique device number for the vfs 448*0Sstevel@tonic-gate * The old way (getudev() + a constantly incrementing 449*0Sstevel@tonic-gate * major number) was wrong because it changes vfs_dev 450*0Sstevel@tonic-gate * across mounts and reboots, which breaks nfs file handles. 451*0Sstevel@tonic-gate * UFS just uses the real dev_t. We can't do that because 452*0Sstevel@tonic-gate * of the way pcfs opens fdisk partitons (the :c and :d 453*0Sstevel@tonic-gate * partitions are on the same dev_t). Though that _might_ 454*0Sstevel@tonic-gate * actually be ok, since the file handle contains an 455*0Sstevel@tonic-gate * absolute block number, it's probably better to make them 456*0Sstevel@tonic-gate * different. So I think we should retain the original 457*0Sstevel@tonic-gate * dev_t, but come up with a different minor number based 458*0Sstevel@tonic-gate * on the logical drive that will _always_ come up the same. 459*0Sstevel@tonic-gate * For now, we steal the upper 6 bits. 460*0Sstevel@tonic-gate */ 461*0Sstevel@tonic-gate #ifdef notdef 462*0Sstevel@tonic-gate /* what should we do here? */ 463*0Sstevel@tonic-gate if (((getminor(xdev) >> 12) & 0x3F) != 0) 464*0Sstevel@tonic-gate printf("whoops - upper bits used!\n"); 465*0Sstevel@tonic-gate #endif 466*0Sstevel@tonic-gate minor = ((dos_ldrive << 12) | getminor(xdev)) & MAXMIN32; 467*0Sstevel@tonic-gate pseudodev = makedevice(getmajor(xdev), minor); 468*0Sstevel@tonic-gate if (vfs_devmounting(pseudodev, vfsp)) { 469*0Sstevel@tonic-gate mutex_exit(&pcfslock); 470*0Sstevel@tonic-gate return (EBUSY); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate if (vfs_devismounted(pseudodev)) { 473*0Sstevel@tonic-gate mutex_exit(&pcfslock); 474*0Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 475*0Sstevel@tonic-gate return (0); 476*0Sstevel@tonic-gate } else { 477*0Sstevel@tonic-gate return (EBUSY); 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate mutex_exit(&pcfslock); 481*0Sstevel@tonic-gate } else { 482*0Sstevel@tonic-gate if (vfs_devmounting(xdev, vfsp)) { 483*0Sstevel@tonic-gate return (EBUSY); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate if (vfs_devismounted(xdev)) 486*0Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) { 487*0Sstevel@tonic-gate return (0); 488*0Sstevel@tonic-gate } else { 489*0Sstevel@tonic-gate return (EBUSY); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate pseudodev = xdev; 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate if (uap->flags & MS_RDONLY) { 495*0Sstevel@tonic-gate vfsp->vfs_flag |= VFS_RDONLY; 496*0Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * Mount the filesystem 501*0Sstevel@tonic-gate */ 502*0Sstevel@tonic-gate devvp = makespecvp(xdev, VBLK); 503*0Sstevel@tonic-gate if (IS_SWAPVP(devvp)) { 504*0Sstevel@tonic-gate VN_RELE(devvp); 505*0Sstevel@tonic-gate return (EBUSY); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * special handling for PCMCIA memory card 510*0Sstevel@tonic-gate * with psuedo floppies organization 511*0Sstevel@tonic-gate */ 512*0Sstevel@tonic-gate if (dos_ldrive == 0 && pcfs_psuedo_floppy(xdev)) { 513*0Sstevel@tonic-gate dosstart = (daddr_t)0; 514*0Sstevel@tonic-gate fattype = PCFS_PCMCIA_NO_CIS; 515*0Sstevel@tonic-gate } else { 516*0Sstevel@tonic-gate if (error = pc_getfattype(devvp, dos_ldrive, &dosstart, 517*0Sstevel@tonic-gate &fattype)) { 518*0Sstevel@tonic-gate VN_RELE(devvp); 519*0Sstevel@tonic-gate return (error); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate (void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0, B_INVAL, cr); 524*0Sstevel@tonic-gate fsp = kmem_zalloc((uint_t)sizeof (struct pcfs), KM_SLEEP); 525*0Sstevel@tonic-gate fsp->pcfs_vfs = vfsp; 526*0Sstevel@tonic-gate fsp->pcfs_flags = fattype; 527*0Sstevel@tonic-gate fsp->pcfs_devvp = devvp; 528*0Sstevel@tonic-gate fsp->pcfs_xdev = xdev; 529*0Sstevel@tonic-gate fsp->pcfs_ldrv = dos_ldrive; 530*0Sstevel@tonic-gate fsp->pcfs_dosstart = dosstart; 531*0Sstevel@tonic-gate mutex_init(&fsp->pcfs_lock, NULL, MUTEX_DEFAULT, NULL); 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate /* set the "nocheck" flag if volmgt is managing this volume */ 534*0Sstevel@tonic-gate info.vii_pathlen = 0; 535*0Sstevel@tonic-gate info.vii_devpath = 0; 536*0Sstevel@tonic-gate error = cdev_ioctl(fsp->pcfs_xdev, VOLIOCINFO, (intptr_t)&info, 537*0Sstevel@tonic-gate FKIOCTL|FREAD, kcred, &rval); 538*0Sstevel@tonic-gate if (error == 0) { 539*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_NOCHK; 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_PCFS_HIDDEN, NULL)) 543*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_HIDDEN; 544*0Sstevel@tonic-gate if (vfs_optionisset(vfsp, MNTOPT_PCFS_FOLDCASE, NULL)) 545*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_FOLDCASE; 546*0Sstevel@tonic-gate vfsp->vfs_dev = pseudodev; 547*0Sstevel@tonic-gate vfsp->vfs_fstype = pcfstype; 548*0Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, pseudodev, pcfstype); 549*0Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)fsp; 550*0Sstevel@tonic-gate vfsp->vfs_bcount = 0; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate error = pc_verify(fsp); 553*0Sstevel@tonic-gate if (error) { 554*0Sstevel@tonic-gate VN_RELE(devvp); 555*0Sstevel@tonic-gate mutex_destroy(&fsp->pcfs_lock); 556*0Sstevel@tonic-gate kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 557*0Sstevel@tonic-gate return (error); 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate vfsp->vfs_bsize = fsp->pcfs_clsize; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate mutex_enter(&pcfslock); 562*0Sstevel@tonic-gate fsp->pcfs_nxt = pc_mounttab; 563*0Sstevel@tonic-gate pc_mounttab = fsp; 564*0Sstevel@tonic-gate mutex_exit(&pcfslock); 565*0Sstevel@tonic-gate return (0); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate /* 569*0Sstevel@tonic-gate * vfs operations 570*0Sstevel@tonic-gate */ 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* ARGSUSED */ 573*0Sstevel@tonic-gate static int 574*0Sstevel@tonic-gate pcfs_unmount( 575*0Sstevel@tonic-gate struct vfs *vfsp, 576*0Sstevel@tonic-gate int flag, 577*0Sstevel@tonic-gate struct cred *cr) 578*0Sstevel@tonic-gate { 579*0Sstevel@tonic-gate struct pcfs *fsp, *fsp1; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 582*0Sstevel@tonic-gate return (EPERM); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * forced unmount is not supported by this file system 586*0Sstevel@tonic-gate * and thus, ENOTSUP, is being returned. 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate if (flag & MS_FORCE) 589*0Sstevel@tonic-gate return (ENOTSUP); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate PC_DPRINTF0(4, "pcfs_unmount\n"); 592*0Sstevel@tonic-gate fsp = VFSTOPCFS(vfsp); 593*0Sstevel@tonic-gate /* 594*0Sstevel@tonic-gate * We don't have to lock fsp because the VVFSLOCK in vfs layer will 595*0Sstevel@tonic-gate * prevent lookuppn from crossing the mount point. 596*0Sstevel@tonic-gate */ 597*0Sstevel@tonic-gate if (fsp->pcfs_nrefs) { 598*0Sstevel@tonic-gate return (EBUSY); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate /* 602*0Sstevel@tonic-gate * Allow an unmount (regardless of state) if the fs instance has 603*0Sstevel@tonic-gate * been marked as beyond recovery. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 606*0Sstevel@tonic-gate mutex_enter(&pcfslock); 607*0Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 608*0Sstevel@tonic-gate pc_diskchanged(fsp); 609*0Sstevel@tonic-gate rw_exit(&pcnodes_lock); 610*0Sstevel@tonic-gate mutex_exit(&pcfslock); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* now there should be no pcp node on pcfhead or pcdhead. */ 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate mutex_enter(&pcfslock); 616*0Sstevel@tonic-gate if (fsp == pc_mounttab) { 617*0Sstevel@tonic-gate pc_mounttab = fsp->pcfs_nxt; 618*0Sstevel@tonic-gate } else { 619*0Sstevel@tonic-gate for (fsp1 = pc_mounttab; fsp1 != NULL; fsp1 = fsp1->pcfs_nxt) 620*0Sstevel@tonic-gate if (fsp1->pcfs_nxt == fsp) 621*0Sstevel@tonic-gate fsp1->pcfs_nxt = fsp->pcfs_nxt; 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate if (fsp->pcfs_fatp != (uchar_t *)0) { 625*0Sstevel@tonic-gate pc_invalfat(fsp); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate mutex_exit(&pcfslock); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate VN_RELE(fsp->pcfs_devvp); 630*0Sstevel@tonic-gate mutex_destroy(&fsp->pcfs_lock); 631*0Sstevel@tonic-gate kmem_free(fsp, (uint_t)sizeof (struct pcfs)); 632*0Sstevel@tonic-gate return (0); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate /* 636*0Sstevel@tonic-gate * find root of pcfs 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate static int 639*0Sstevel@tonic-gate pcfs_root( 640*0Sstevel@tonic-gate struct vfs *vfsp, 641*0Sstevel@tonic-gate struct vnode **vpp) 642*0Sstevel@tonic-gate { 643*0Sstevel@tonic-gate struct pcfs *fsp; 644*0Sstevel@tonic-gate struct pcnode *pcp; 645*0Sstevel@tonic-gate int error; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate fsp = VFSTOPCFS(vfsp); 648*0Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 649*0Sstevel@tonic-gate return (error); 650*0Sstevel@tonic-gate pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 651*0Sstevel@tonic-gate PC_DPRINTF2(9, "pcfs_root(0x%p) pcp= 0x%p\n", 652*0Sstevel@tonic-gate (void *)vfsp, (void *)pcp); 653*0Sstevel@tonic-gate pc_unlockfs(fsp); 654*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 655*0Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 656*0Sstevel@tonic-gate return (0); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* 660*0Sstevel@tonic-gate * Get file system statistics. 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate static int 663*0Sstevel@tonic-gate pcfs_statvfs( 664*0Sstevel@tonic-gate struct vfs *vfsp, 665*0Sstevel@tonic-gate struct statvfs64 *sp) 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate struct pcfs *fsp; 668*0Sstevel@tonic-gate int error; 669*0Sstevel@tonic-gate dev32_t d32; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate fsp = VFSTOPCFS(vfsp); 672*0Sstevel@tonic-gate error = pc_getfat(fsp); 673*0Sstevel@tonic-gate if (error) 674*0Sstevel@tonic-gate return (error); 675*0Sstevel@tonic-gate bzero(sp, sizeof (*sp)); 676*0Sstevel@tonic-gate sp->f_bsize = sp->f_frsize = fsp->pcfs_clsize; 677*0Sstevel@tonic-gate sp->f_blocks = (fsblkcnt64_t)fsp->pcfs_ncluster; 678*0Sstevel@tonic-gate sp->f_bavail = sp->f_bfree = (fsblkcnt64_t)pc_freeclusters(fsp); 679*0Sstevel@tonic-gate sp->f_files = (fsfilcnt64_t)-1; 680*0Sstevel@tonic-gate sp->f_ffree = (fsfilcnt64_t)-1; 681*0Sstevel@tonic-gate sp->f_favail = (fsfilcnt64_t)-1; 682*0Sstevel@tonic-gate #ifdef notdef 683*0Sstevel@tonic-gate (void) cmpldev(&d32, fsp->pcfs_devvp->v_rdev); 684*0Sstevel@tonic-gate #endif /* notdef */ 685*0Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev); 686*0Sstevel@tonic-gate sp->f_fsid = d32; 687*0Sstevel@tonic-gate (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 688*0Sstevel@tonic-gate sp->f_flag = vf_to_stf(vfsp->vfs_flag); 689*0Sstevel@tonic-gate sp->f_namemax = PCFNAMESIZE; 690*0Sstevel@tonic-gate return (0); 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate static int 694*0Sstevel@tonic-gate pc_syncfsnodes(struct pcfs *fsp) 695*0Sstevel@tonic-gate { 696*0Sstevel@tonic-gate struct pchead *hp; 697*0Sstevel@tonic-gate struct pcnode *pcp; 698*0Sstevel@tonic-gate int error; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate PC_DPRINTF0(7, "pcfs_syncfsnodes\n"); 701*0Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0)) 702*0Sstevel@tonic-gate return (error); 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate if (!(error = pc_syncfat(fsp))) { 705*0Sstevel@tonic-gate hp = pcfhead; 706*0Sstevel@tonic-gate while (hp < & pcfhead [ NPCHASH ]) { 707*0Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_READER); 708*0Sstevel@tonic-gate pcp = hp->pch_forw; 709*0Sstevel@tonic-gate while (pcp != (struct pcnode *)hp) { 710*0Sstevel@tonic-gate if (VFSTOPCFS(PCTOV(pcp) -> v_vfsp) == fsp) 711*0Sstevel@tonic-gate if (error = pc_nodesync(pcp)) 712*0Sstevel@tonic-gate break; 713*0Sstevel@tonic-gate pcp = pcp -> pc_forw; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate rw_exit(&pcnodes_lock); 716*0Sstevel@tonic-gate if (error) 717*0Sstevel@tonic-gate break; 718*0Sstevel@tonic-gate hp++; 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate pc_unlockfs(fsp); 722*0Sstevel@tonic-gate return (error); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate /* 726*0Sstevel@tonic-gate * Flush any pending I/O. 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate /*ARGSUSED*/ 729*0Sstevel@tonic-gate static int 730*0Sstevel@tonic-gate pcfs_sync( 731*0Sstevel@tonic-gate struct vfs *vfsp, 732*0Sstevel@tonic-gate short flag, 733*0Sstevel@tonic-gate struct cred *cr) 734*0Sstevel@tonic-gate { 735*0Sstevel@tonic-gate struct pcfs *fsp; 736*0Sstevel@tonic-gate int error = 0; 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate /* this prevents the filesystem from being umounted. */ 739*0Sstevel@tonic-gate mutex_enter(&pcfslock); 740*0Sstevel@tonic-gate if (vfsp != NULL) { 741*0Sstevel@tonic-gate fsp = VFSTOPCFS(vfsp); 742*0Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_IRRECOV)) { 743*0Sstevel@tonic-gate error = pc_syncfsnodes(fsp); 744*0Sstevel@tonic-gate } else { 745*0Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 746*0Sstevel@tonic-gate pc_diskchanged(fsp); 747*0Sstevel@tonic-gate rw_exit(&pcnodes_lock); 748*0Sstevel@tonic-gate error = EIO; 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate } else { 751*0Sstevel@tonic-gate fsp = pc_mounttab; 752*0Sstevel@tonic-gate while (fsp != NULL) { 753*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) { 754*0Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER); 755*0Sstevel@tonic-gate pc_diskchanged(fsp); 756*0Sstevel@tonic-gate rw_exit(&pcnodes_lock); 757*0Sstevel@tonic-gate error = EIO; 758*0Sstevel@tonic-gate break; 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate error = pc_syncfsnodes(fsp); 761*0Sstevel@tonic-gate if (error) break; 762*0Sstevel@tonic-gate fsp = fsp->pcfs_nxt; 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate mutex_exit(&pcfslock); 766*0Sstevel@tonic-gate return (error); 767*0Sstevel@tonic-gate } 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate int 770*0Sstevel@tonic-gate pc_lockfs(struct pcfs *fsp, int diskchanged, int releasing) 771*0Sstevel@tonic-gate { 772*0Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && !releasing) 773*0Sstevel@tonic-gate return (EIO); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_LOCKED) && (fsp->pcfs_owner == curthread)) { 776*0Sstevel@tonic-gate fsp->pcfs_count++; 777*0Sstevel@tonic-gate } else { 778*0Sstevel@tonic-gate mutex_enter(&fsp->pcfs_lock); 779*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_LOCKED) 780*0Sstevel@tonic-gate panic("pc_lockfs"); 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * We check the IRRECOV bit again just in case somebody 783*0Sstevel@tonic-gate * snuck past the initial check but then got held up before 784*0Sstevel@tonic-gate * they could grab the lock. (And in the meantime someone 785*0Sstevel@tonic-gate * had grabbed the lock and set the bit) 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate if (!diskchanged && !(fsp->pcfs_flags & PCFS_IRRECOV)) 788*0Sstevel@tonic-gate (void) pc_getfat(fsp); 789*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_LOCKED; 790*0Sstevel@tonic-gate fsp->pcfs_owner = curthread; 791*0Sstevel@tonic-gate fsp->pcfs_count++; 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate return (0); 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate void 797*0Sstevel@tonic-gate pc_unlockfs(struct pcfs *fsp) 798*0Sstevel@tonic-gate { 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_LOCKED) == 0) 801*0Sstevel@tonic-gate panic("pc_unlockfs"); 802*0Sstevel@tonic-gate if (--fsp->pcfs_count < 0) 803*0Sstevel@tonic-gate panic("pc_unlockfs: count"); 804*0Sstevel@tonic-gate if (fsp->pcfs_count == 0) { 805*0Sstevel@tonic-gate fsp->pcfs_flags &= ~PCFS_LOCKED; 806*0Sstevel@tonic-gate fsp->pcfs_owner = 0; 807*0Sstevel@tonic-gate mutex_exit(&fsp->pcfs_lock); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate /* 812*0Sstevel@tonic-gate * isDosDrive() 813*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 814*0Sstevel@tonic-gate * and it decides if that's a systid that describes a DOS drive. We 815*0Sstevel@tonic-gate * use systid values defined in sys/dktp/fdisk.h. 816*0Sstevel@tonic-gate */ 817*0Sstevel@tonic-gate static int 818*0Sstevel@tonic-gate isDosDrive(uchar_t checkMe) 819*0Sstevel@tonic-gate { 820*0Sstevel@tonic-gate return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 821*0Sstevel@tonic-gate (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 822*0Sstevel@tonic-gate (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 823*0Sstevel@tonic-gate (checkMe == DIAGPART)); 824*0Sstevel@tonic-gate } 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate /* 827*0Sstevel@tonic-gate * isDosExtended() 828*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 829*0Sstevel@tonic-gate * and it decides if that's a systid that describes an extended DOS 830*0Sstevel@tonic-gate * partition. 831*0Sstevel@tonic-gate */ 832*0Sstevel@tonic-gate static int 833*0Sstevel@tonic-gate isDosExtended(uchar_t checkMe) 834*0Sstevel@tonic-gate { 835*0Sstevel@tonic-gate return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate /* 839*0Sstevel@tonic-gate * isBootPart() 840*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 841*0Sstevel@tonic-gate * and it decides if that's a systid that describes a Solaris boot 842*0Sstevel@tonic-gate * partition. 843*0Sstevel@tonic-gate */ 844*0Sstevel@tonic-gate static int 845*0Sstevel@tonic-gate isBootPart(uchar_t checkMe) 846*0Sstevel@tonic-gate { 847*0Sstevel@tonic-gate return (checkMe == X86BOOT); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * noLogicalDrive() 852*0Sstevel@tonic-gate * Display error message about not being able to find a logical 853*0Sstevel@tonic-gate * drive. 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate static void 856*0Sstevel@tonic-gate noLogicalDrive(int requested) 857*0Sstevel@tonic-gate { 858*0Sstevel@tonic-gate if (requested == BOOT_PARTITION_DRIVE) { 859*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: no boot partition"); 860*0Sstevel@tonic-gate } else { 861*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: no such logical drive"); 862*0Sstevel@tonic-gate } 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate /* 866*0Sstevel@tonic-gate * findTheDrive() 867*0Sstevel@tonic-gate * Discover offset of the requested logical drive, and return 868*0Sstevel@tonic-gate * that offset (startSector), the systid of that drive (sysid), 869*0Sstevel@tonic-gate * and a buffer pointer (bp), with the buffer contents being 870*0Sstevel@tonic-gate * the first sector of the logical drive (i.e., the sector that 871*0Sstevel@tonic-gate * contains the BPB for that drive). 872*0Sstevel@tonic-gate */ 873*0Sstevel@tonic-gate static int 874*0Sstevel@tonic-gate findTheDrive(dev_t dev, int askedFor, int *error, buf_t **bp, 875*0Sstevel@tonic-gate daddr_t *startSector, uchar_t *sysid) 876*0Sstevel@tonic-gate { 877*0Sstevel@tonic-gate struct ipart dosp[FD_NUMPART]; /* incore fdisk partition structure */ 878*0Sstevel@tonic-gate struct mboot *dosp_ptr; /* boot structure pointer */ 879*0Sstevel@tonic-gate daddr_t lastseek = 0; /* Disk block we sought previously */ 880*0Sstevel@tonic-gate daddr_t diskblk = 0; /* Disk block to get */ 881*0Sstevel@tonic-gate daddr_t xstartsect; /* base of Extended DOS partition */ 882*0Sstevel@tonic-gate int logicalDriveCount = 0; /* Count of logical drives seen */ 883*0Sstevel@tonic-gate int extendedPart = -1; /* index of extended dos partition */ 884*0Sstevel@tonic-gate int primaryPart = -1; /* index of primary dos partition */ 885*0Sstevel@tonic-gate int bootPart = -1; /* index of a Solaris boot partition */ 886*0Sstevel@tonic-gate int xnumsect = -1; /* length of extended DOS partition */ 887*0Sstevel@tonic-gate int driveIndex; /* computed FDISK table index */ 888*0Sstevel@tonic-gate int i; 889*0Sstevel@tonic-gate /* 890*0Sstevel@tonic-gate * Count of drives in the current extended partition's 891*0Sstevel@tonic-gate * FDISK table, and indexes of the drives themselves. 892*0Sstevel@tonic-gate */ 893*0Sstevel@tonic-gate int extndDrives[FD_NUMPART]; 894*0Sstevel@tonic-gate int numDrives = 0; 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate /* 897*0Sstevel@tonic-gate * Count of drives (beyond primary) in master boot record's 898*0Sstevel@tonic-gate * FDISK table, and indexes of the drives themselves. 899*0Sstevel@tonic-gate */ 900*0Sstevel@tonic-gate int extraDrives[FD_NUMPART]; 901*0Sstevel@tonic-gate int numExtraDrives = 0; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate /* 904*0Sstevel@tonic-gate * Copy from disk block into memory aligned structure for fdisk usage. 905*0Sstevel@tonic-gate */ 906*0Sstevel@tonic-gate dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 907*0Sstevel@tonic-gate bcopy(dosp_ptr->parts, dosp, sizeof (struct ipart) * FD_NUMPART); 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * Get a summary of what is in the Master FDISK table. 911*0Sstevel@tonic-gate * Normally we expect to find one partition marked as a DOS drive. 912*0Sstevel@tonic-gate * This partition is the one Windows calls the primary dos partition. 913*0Sstevel@tonic-gate * If the machine has any logical drives then we also expect 914*0Sstevel@tonic-gate * to find a partition marked as an extended DOS partition. 915*0Sstevel@tonic-gate * 916*0Sstevel@tonic-gate * Sometimes we'll find multiple partitions marked as DOS drives. 917*0Sstevel@tonic-gate * The Solaris fdisk program allows these partitions 918*0Sstevel@tonic-gate * to be created, but Windows fdisk no longer does. We still need 919*0Sstevel@tonic-gate * to support these, though, since Windows does. We also need to fix 920*0Sstevel@tonic-gate * our fdisk to behave like the Windows version. 921*0Sstevel@tonic-gate * 922*0Sstevel@tonic-gate * It turns out that some off-the-shelf media have *only* an 923*0Sstevel@tonic-gate * Extended partition, so we need to deal with that case as well. 924*0Sstevel@tonic-gate * 925*0Sstevel@tonic-gate * Only a single (the first) Extended or Boot Partition will 926*0Sstevel@tonic-gate * be recognized. Any others will be ignored. 927*0Sstevel@tonic-gate */ 928*0Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 929*0Sstevel@tonic-gate if (isDosDrive(dosp[i].systid)) { 930*0Sstevel@tonic-gate if (primaryPart < 0) { 931*0Sstevel@tonic-gate logicalDriveCount++; 932*0Sstevel@tonic-gate primaryPart = i; 933*0Sstevel@tonic-gate } else { 934*0Sstevel@tonic-gate extraDrives[numExtraDrives++] = i; 935*0Sstevel@tonic-gate } 936*0Sstevel@tonic-gate continue; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate if ((extendedPart < 0) && isDosExtended(dosp[i].systid)) { 939*0Sstevel@tonic-gate extendedPart = i; 940*0Sstevel@tonic-gate continue; 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate if ((bootPart < 0) && isBootPart(dosp[i].systid)) { 943*0Sstevel@tonic-gate bootPart = i; 944*0Sstevel@tonic-gate continue; 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate } 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if (askedFor == BOOT_PARTITION_DRIVE) { 949*0Sstevel@tonic-gate if (bootPart < 0) { 950*0Sstevel@tonic-gate noLogicalDrive(askedFor); 951*0Sstevel@tonic-gate *error = EINVAL; 952*0Sstevel@tonic-gate return (0); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate *sysid = dosp[bootPart].systid; 955*0Sstevel@tonic-gate *startSector = ltohi(dosp[bootPart].relsect); 956*0Sstevel@tonic-gate return (1); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (askedFor == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 960*0Sstevel@tonic-gate *sysid = dosp[primaryPart].systid; 961*0Sstevel@tonic-gate *startSector = ltohi(dosp[primaryPart].relsect); 962*0Sstevel@tonic-gate return (1); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate /* 966*0Sstevel@tonic-gate * We are not looking for the C: drive (or the primary drive 967*0Sstevel@tonic-gate * was not found), so we had better have an extended partition 968*0Sstevel@tonic-gate * or extra drives in the Master FDISK table. 969*0Sstevel@tonic-gate */ 970*0Sstevel@tonic-gate if ((extendedPart < 0) && (numExtraDrives == 0)) { 971*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: no extended dos partition"); 972*0Sstevel@tonic-gate noLogicalDrive(askedFor); 973*0Sstevel@tonic-gate *error = EINVAL; 974*0Sstevel@tonic-gate return (0); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate if (extendedPart >= 0) { 978*0Sstevel@tonic-gate diskblk = xstartsect = ltohi(dosp[extendedPart].relsect); 979*0Sstevel@tonic-gate xnumsect = ltohi(dosp[extendedPart].numsect); 980*0Sstevel@tonic-gate do { 981*0Sstevel@tonic-gate /* 982*0Sstevel@tonic-gate * If the seek would not cause us to change 983*0Sstevel@tonic-gate * position on the drive, then we're out of 984*0Sstevel@tonic-gate * extended partitions to examine. 985*0Sstevel@tonic-gate */ 986*0Sstevel@tonic-gate if (diskblk == lastseek) 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate logicalDriveCount += numDrives; 989*0Sstevel@tonic-gate /* 990*0Sstevel@tonic-gate * Seek the next extended partition, and find 991*0Sstevel@tonic-gate * logical drives within it. 992*0Sstevel@tonic-gate */ 993*0Sstevel@tonic-gate brelse(*bp); 994*0Sstevel@tonic-gate *bp = bread(dev, diskblk, PC_SAFESECSIZE); 995*0Sstevel@tonic-gate if ((*bp)->b_flags & B_ERROR) { 996*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_getfattype: read error\n"); 997*0Sstevel@tonic-gate *error = EIO; 998*0Sstevel@tonic-gate return (0); 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate lastseek = diskblk; 1001*0Sstevel@tonic-gate dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1002*0Sstevel@tonic-gate if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 1003*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: " 1004*0Sstevel@tonic-gate "extended partition signature err"); 1005*0Sstevel@tonic-gate *error = EINVAL; 1006*0Sstevel@tonic-gate return (0); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate bcopy(dosp_ptr->parts, dosp, 1009*0Sstevel@tonic-gate sizeof (struct ipart) * FD_NUMPART); 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Count up drives, and track where the next 1012*0Sstevel@tonic-gate * extended partition is in case we need it. We 1013*0Sstevel@tonic-gate * are expecting only one extended partition. If 1014*0Sstevel@tonic-gate * there is more than one we'll only go to the 1015*0Sstevel@tonic-gate * first one we see, but warn about ignoring. 1016*0Sstevel@tonic-gate */ 1017*0Sstevel@tonic-gate numDrives = 0; 1018*0Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 1019*0Sstevel@tonic-gate if (isDosDrive(dosp[i].systid)) { 1020*0Sstevel@tonic-gate extndDrives[numDrives++] = i; 1021*0Sstevel@tonic-gate continue; 1022*0Sstevel@tonic-gate } else if (isDosExtended(dosp[i].systid)) { 1023*0Sstevel@tonic-gate if (diskblk != lastseek) { 1024*0Sstevel@tonic-gate /* 1025*0Sstevel@tonic-gate * Already found an extended 1026*0Sstevel@tonic-gate * partition in this table. 1027*0Sstevel@tonic-gate */ 1028*0Sstevel@tonic-gate cmn_err(CE_NOTE, 1029*0Sstevel@tonic-gate "!pcfs: ignoring unexpected" 1030*0Sstevel@tonic-gate " additional extended" 1031*0Sstevel@tonic-gate " partition"); 1032*0Sstevel@tonic-gate continue; 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate diskblk = xstartsect + 1035*0Sstevel@tonic-gate ltohi(dosp[i].relsect); 1036*0Sstevel@tonic-gate continue; 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate } 1039*0Sstevel@tonic-gate } while (askedFor > logicalDriveCount + numDrives); 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate if (askedFor <= logicalDriveCount + numDrives) { 1042*0Sstevel@tonic-gate /* 1043*0Sstevel@tonic-gate * The number of logical drives we've found thus 1044*0Sstevel@tonic-gate * far is enough to get us to the one we were 1045*0Sstevel@tonic-gate * searching for. 1046*0Sstevel@tonic-gate */ 1047*0Sstevel@tonic-gate driveIndex = logicalDriveCount + numDrives - askedFor; 1048*0Sstevel@tonic-gate *sysid = dosp[extndDrives[driveIndex]].systid; 1049*0Sstevel@tonic-gate *startSector = 1050*0Sstevel@tonic-gate ltohi(dosp[extndDrives[driveIndex]].relsect) + 1051*0Sstevel@tonic-gate lastseek; 1052*0Sstevel@tonic-gate if (*startSector > (xstartsect + xnumsect)) { 1053*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: extended partition " 1054*0Sstevel@tonic-gate "values bad"); 1055*0Sstevel@tonic-gate *error = EINVAL; 1056*0Sstevel@tonic-gate return (0); 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate return (1); 1059*0Sstevel@tonic-gate } else { 1060*0Sstevel@tonic-gate /* 1061*0Sstevel@tonic-gate * We ran out of extended dos partition 1062*0Sstevel@tonic-gate * drives. The only hope now is to go 1063*0Sstevel@tonic-gate * back to extra drives defined in the master 1064*0Sstevel@tonic-gate * fdisk table. But we overwrote that table 1065*0Sstevel@tonic-gate * already, so we must load it in again. 1066*0Sstevel@tonic-gate */ 1067*0Sstevel@tonic-gate logicalDriveCount += numDrives; 1068*0Sstevel@tonic-gate brelse(*bp); 1069*0Sstevel@tonic-gate *bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1070*0Sstevel@tonic-gate if ((*bp)->b_flags & B_ERROR) { 1071*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1072*0Sstevel@tonic-gate *error = EIO; 1073*0Sstevel@tonic-gate return (0); 1074*0Sstevel@tonic-gate } 1075*0Sstevel@tonic-gate dosp_ptr = (struct mboot *)(*bp)->b_un.b_addr; 1076*0Sstevel@tonic-gate bcopy(dosp_ptr->parts, dosp, 1077*0Sstevel@tonic-gate sizeof (struct ipart) * FD_NUMPART); 1078*0Sstevel@tonic-gate } 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate /* 1081*0Sstevel@tonic-gate * Still haven't found the drive, is it an extra 1082*0Sstevel@tonic-gate * drive defined in the main FDISK table? 1083*0Sstevel@tonic-gate */ 1084*0Sstevel@tonic-gate if (askedFor <= logicalDriveCount + numExtraDrives) { 1085*0Sstevel@tonic-gate driveIndex = logicalDriveCount + numExtraDrives - askedFor; 1086*0Sstevel@tonic-gate *sysid = dosp[extraDrives[driveIndex]].systid; 1087*0Sstevel@tonic-gate *startSector = ltohi(dosp[extraDrives[driveIndex]].relsect); 1088*0Sstevel@tonic-gate return (1); 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate /* 1091*0Sstevel@tonic-gate * Still haven't found the drive, and there is 1092*0Sstevel@tonic-gate * nowhere else to look. 1093*0Sstevel@tonic-gate */ 1094*0Sstevel@tonic-gate noLogicalDrive(askedFor); 1095*0Sstevel@tonic-gate *error = EINVAL; 1096*0Sstevel@tonic-gate return (0); 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * Get the FAT type for the DOS medium. 1101*0Sstevel@tonic-gate * 1102*0Sstevel@tonic-gate * We look at sector 0 and determine if we are looking at an FDISK table 1103*0Sstevel@tonic-gate * or a BIOS Parameter Block (BPB). Most of the time, if its a floppy 1104*0Sstevel@tonic-gate * we'll be looking at a BPB and if we're looking at a hard drive we'll be 1105*0Sstevel@tonic-gate * examining an FDISK table. Those fun exceptions do happen, though. 1106*0Sstevel@tonic-gate * 1107*0Sstevel@tonic-gate * If we are looking at a BPB, we can calculate and verify the FAT size. 1108*0Sstevel@tonic-gate * If we are looking at an FDISK partition table, we scan the partition 1109*0Sstevel@tonic-gate * table for the requested logical volume. 1110*0Sstevel@tonic-gate */ 1111*0Sstevel@tonic-gate static int 1112*0Sstevel@tonic-gate pc_getfattype( 1113*0Sstevel@tonic-gate struct vnode *devvp, 1114*0Sstevel@tonic-gate int ldrive, 1115*0Sstevel@tonic-gate daddr_t *strtsectp, 1116*0Sstevel@tonic-gate int *fattypep) 1117*0Sstevel@tonic-gate { 1118*0Sstevel@tonic-gate struct mboot *dosp_ptr; /* boot structure pointer */ 1119*0Sstevel@tonic-gate struct bootsec *bootp, *bpbp; /* for detailed sector examination */ 1120*0Sstevel@tonic-gate uchar_t *cp; /* for searching out FAT string */ 1121*0Sstevel@tonic-gate uint_t overhead; /* sectors not part of file area */ 1122*0Sstevel@tonic-gate uint_t numclusters; /* number of clusters in file area */ 1123*0Sstevel@tonic-gate uint_t bytesoffat; /* computed number of bytes in a FAT */ 1124*0Sstevel@tonic-gate int secsize; /* Sector size in bytes/sec */ 1125*0Sstevel@tonic-gate buf_t *bp = NULL; /* Disk buffer pointer */ 1126*0Sstevel@tonic-gate int rval = 0; 1127*0Sstevel@tonic-gate uchar_t sysid = 0; /* System ID character */ 1128*0Sstevel@tonic-gate dev_t dev = devvp->v_rdev; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate *strtsectp = (daddr_t)0; 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate /* 1133*0Sstevel@tonic-gate * Open the device so we can check out the BPB or FDISK table, 1134*0Sstevel@tonic-gate * then read in the sector. 1135*0Sstevel@tonic-gate */ 1136*0Sstevel@tonic-gate PC_DPRINTF2(5, "pc_getfattype: dev=%x ldrive=%x ", (int)dev, ldrive); 1137*0Sstevel@tonic-gate if (rval = VOP_OPEN(&devvp, FREAD, CRED())) { 1138*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getfattype: open error=%d\n", rval); 1139*0Sstevel@tonic-gate return (rval); 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate /* 1143*0Sstevel@tonic-gate * Read block 0 from device 1144*0Sstevel@tonic-gate */ 1145*0Sstevel@tonic-gate bp = bread(dev, (daddr_t)0, PC_SAFESECSIZE); 1146*0Sstevel@tonic-gate if (bp->b_flags & B_ERROR) { 1147*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1148*0Sstevel@tonic-gate rval = EIO; 1149*0Sstevel@tonic-gate goto out; 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate /* 1153*0Sstevel@tonic-gate * If this is a logical volume with a FAT file system, 1154*0Sstevel@tonic-gate * then we expect to find a "file system boot sector" 1155*0Sstevel@tonic-gate * (also called a BIOS Perameter Block -- or BPB) in 1156*0Sstevel@tonic-gate * the first physical sector. 1157*0Sstevel@tonic-gate */ 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate /* 1160*0Sstevel@tonic-gate * The word "FAT" is encoded into the BPB beginning at 1161*0Sstevel@tonic-gate * PCFS_TYPESTRING_OFFSET16 in 12 and 16 bit FATs. It is 1162*0Sstevel@tonic-gate * encoded at FS_TYPESTRING_OFFSET32 in 32 bit FATs. 1163*0Sstevel@tonic-gate */ 1164*0Sstevel@tonic-gate cp = (uchar_t *)bp->b_un.b_addr; 1165*0Sstevel@tonic-gate if (*(cp + PCFS_TYPESTRING_OFFSET16) == 'F' && 1166*0Sstevel@tonic-gate *(cp + PCFS_TYPESTRING_OFFSET16 + 1) == 'A' && 1167*0Sstevel@tonic-gate *(cp + PCFS_TYPESTRING_OFFSET16 + 2) == 'T') { 1168*0Sstevel@tonic-gate PC_DPRINTF0(5, "Found the FAT string at 12/16 location\n"); 1169*0Sstevel@tonic-gate /* 1170*0Sstevel@tonic-gate * Compute a bits/fat value 1171*0Sstevel@tonic-gate */ 1172*0Sstevel@tonic-gate bpbp = (struct bootsec *)bp->b_un.b_addr; 1173*0Sstevel@tonic-gate secsize = (int)ltohs(bpbp->bps[0]); 1174*0Sstevel@tonic-gate /* 1175*0Sstevel@tonic-gate * Check for bogus sector size - 1176*0Sstevel@tonic-gate * fat should be at least 1 sector 1177*0Sstevel@tonic-gate * If anything looks weird, we have to bail and try looking 1178*0Sstevel@tonic-gate * for an FDISK table instead. 1179*0Sstevel@tonic-gate */ 1180*0Sstevel@tonic-gate if (secsize < 512 || (int)ltohs(bpbp->fatsec) < 1 || 1181*0Sstevel@tonic-gate bpbp->nfat < 1 || bpbp->spcl < 1) { 1182*0Sstevel@tonic-gate PC_DPRINTF4(5, "One or more BPB fields bad\n" 1183*0Sstevel@tonic-gate "bytes/sec = %d, sec/fat = %d, numfats = %d, " 1184*0Sstevel@tonic-gate "sec/clust = %d\n", secsize, 1185*0Sstevel@tonic-gate (int)ltohs(bpbp->fatsec), bpbp->nfat, bpbp->spcl); 1186*0Sstevel@tonic-gate goto lookforfdisk; 1187*0Sstevel@tonic-gate } 1188*0Sstevel@tonic-gate 1189*0Sstevel@tonic-gate overhead = bpbp->nfat * ltohs(bpbp->fatsec); 1190*0Sstevel@tonic-gate overhead += ltohs(bpbp->res_sec[0]); 1191*0Sstevel@tonic-gate overhead += (ltohs(bpbp->rdirents[0]) * 1192*0Sstevel@tonic-gate sizeof (struct pcdir)) / secsize; 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate numclusters = ((ltohs(bpbp->numsect[0]) ? 1195*0Sstevel@tonic-gate ltohs(bpbp->numsect[0]) : ltohi(bpbp->totalsec)) - 1196*0Sstevel@tonic-gate overhead) / bpbp->spcl; 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate /* 1199*0Sstevel@tonic-gate * If the number of clusters looks bad, go look for an 1200*0Sstevel@tonic-gate * FDISK table. 1201*0Sstevel@tonic-gate */ 1202*0Sstevel@tonic-gate if (numclusters < 1) { 1203*0Sstevel@tonic-gate PC_DPRINTF1(5, "num clusters is bad ( = %d )\n", 1204*0Sstevel@tonic-gate numclusters); 1205*0Sstevel@tonic-gate goto lookforfdisk; 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate /* 1209*0Sstevel@tonic-gate * The number of bytes of FAT determines the maximum number 1210*0Sstevel@tonic-gate * of entries of a given size that FAT can contain. 1211*0Sstevel@tonic-gate * The FAT can only contain (bytes of FAT)*8/12 12-bit entries 1212*0Sstevel@tonic-gate * and (bytes of FAT)*8/16 16-bit entries. 1213*0Sstevel@tonic-gate */ 1214*0Sstevel@tonic-gate bytesoffat = ltohs(bpbp->fatsec) * secsize; 1215*0Sstevel@tonic-gate PC_DPRINTF1(5, "Computed bytes of fat = %u\n", bytesoffat); 1216*0Sstevel@tonic-gate if ((bytesoffat * 2 / 3) >= numclusters && 1217*0Sstevel@tonic-gate *(cp + PCFS_TYPESTRING_OFFSET16 + 4) == '2') { 1218*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 12-bit FAT\n"); 1219*0Sstevel@tonic-gate *fattypep = 0; 1220*0Sstevel@tonic-gate rval = 0; 1221*0Sstevel@tonic-gate goto out; 1222*0Sstevel@tonic-gate } else if (*(cp + PCFS_TYPESTRING_OFFSET16 + 4) == '6') { 1223*0Sstevel@tonic-gate /* 1224*0Sstevel@tonic-gate * this check can result in a false positive, where 1225*0Sstevel@tonic-gate * we believe a FAT12 filesystem to be a FAT16 one 1226*0Sstevel@tonic-gate * (if the type recorded in the header block lies). 1227*0Sstevel@tonic-gate * we recover from being lied to, in 'pc_getfat' by 1228*0Sstevel@tonic-gate * Forcing fat12 over fat16, if 1229*0Sstevel@tonic-gate * 'pcfs_fatsec <= 12' and 1230*0Sstevel@tonic-gate * '(byteoffat * 2 / 3) >= numclusters' 1231*0Sstevel@tonic-gate * the obvious check would have been: 1232*0Sstevel@tonic-gate * else if ((bytesoffat / 2) >= numclusters && 1233*0Sstevel@tonic-gate * *(cp + PCFS_TYPESTRING_OFFSET16 + 4) == '6') 1234*0Sstevel@tonic-gate */ 1235*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 16-bit FAT\n"); 1236*0Sstevel@tonic-gate *fattypep = PCFS_FAT16; 1237*0Sstevel@tonic-gate rval = 0; 1238*0Sstevel@tonic-gate goto out; 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate goto lookforfdisk; 1241*0Sstevel@tonic-gate } else if (*(cp + PCFS_TYPESTRING_OFFSET32) == 'F' && 1242*0Sstevel@tonic-gate *(cp + PCFS_TYPESTRING_OFFSET32 + 1) == 'A' && 1243*0Sstevel@tonic-gate *(cp + PCFS_TYPESTRING_OFFSET32 + 2) == 'T') { 1244*0Sstevel@tonic-gate PC_DPRINTF0(5, "Found the FAT string at 32 location\n"); 1245*0Sstevel@tonic-gate bpbp = (struct bootsec *)bp->b_un.b_addr; 1246*0Sstevel@tonic-gate if ((int)ltohs(bpbp->fatsec) != 0) { 1247*0Sstevel@tonic-gate /* 1248*0Sstevel@tonic-gate * Not a good sign, we expect it to be zero if 1249*0Sstevel@tonic-gate * this is really a FAT32 BPB. All we can do 1250*0Sstevel@tonic-gate * is consider the string an anomaly, and go look 1251*0Sstevel@tonic-gate * for an FDISK table. 1252*0Sstevel@tonic-gate */ 1253*0Sstevel@tonic-gate PC_DPRINTF0(5, "But secs/fat non-zero\n"); 1254*0Sstevel@tonic-gate goto lookforfdisk; 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 32-bit FAT\n"); 1257*0Sstevel@tonic-gate *fattypep = PCFS_FAT32; 1258*0Sstevel@tonic-gate rval = 0; 1259*0Sstevel@tonic-gate goto out; 1260*0Sstevel@tonic-gate } else { 1261*0Sstevel@tonic-gate /* 1262*0Sstevel@tonic-gate * We've got some legacy cases (like the stuff fdformat 1263*0Sstevel@tonic-gate * produces!). Basically this is pre-MSDOS4.0 FATs. 1264*0Sstevel@tonic-gate * 1265*0Sstevel@tonic-gate * We'll declare a match if: 1266*0Sstevel@tonic-gate * 1. Bytes/Sector and other fields seem reasonable 1267*0Sstevel@tonic-gate * 2. The media byte matches a known one. 1268*0Sstevel@tonic-gate * 1269*0Sstevel@tonic-gate * If the media byte indicates a floppy we'll 1270*0Sstevel@tonic-gate * assume FAT12, otherwise we'll assume FAT16. 1271*0Sstevel@tonic-gate */ 1272*0Sstevel@tonic-gate bpbp = (struct bootsec *)bp->b_un.b_addr; 1273*0Sstevel@tonic-gate secsize = (int)ltohs(bpbp->bps[0]); 1274*0Sstevel@tonic-gate if (secsize && secsize % 512 == 0 && 1275*0Sstevel@tonic-gate ltohs(bpbp->fatsec) > 0 && bpbp->nfat > 0 && 1276*0Sstevel@tonic-gate bpbp->spcl > 0 && ltohs(bpbp->res_sec[0]) >= 1 && 1277*0Sstevel@tonic-gate ltohs(bpbp->numsect[0]) > 0) { 1278*0Sstevel@tonic-gate switch (bpbp->mediadesriptor) { 1279*0Sstevel@tonic-gate case SS8SPT: 1280*0Sstevel@tonic-gate case DS8SPT: 1281*0Sstevel@tonic-gate case SS9SPT: 1282*0Sstevel@tonic-gate case DS9SPT: 1283*0Sstevel@tonic-gate case DS18SPT: 1284*0Sstevel@tonic-gate case DS9_15SPT: 1285*0Sstevel@tonic-gate *fattypep = 0; 1286*0Sstevel@tonic-gate rval = 0; 1287*0Sstevel@tonic-gate goto out; 1288*0Sstevel@tonic-gate case MD_FIXED: 1289*0Sstevel@tonic-gate *fattypep = PCFS_FAT16; 1290*0Sstevel@tonic-gate rval = 0; 1291*0Sstevel@tonic-gate goto out; 1292*0Sstevel@tonic-gate default: 1293*0Sstevel@tonic-gate goto lookforfdisk; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate } 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate lookforfdisk: 1299*0Sstevel@tonic-gate /* 1300*0Sstevel@tonic-gate * If we got here then we didn't find a BPB. 1301*0Sstevel@tonic-gate * We now assume we are looking at the start of a hard drive, 1302*0Sstevel@tonic-gate * where the first sector will be a Master Boot Record (MBR). 1303*0Sstevel@tonic-gate * The MBR contains a partition table (also called an FDISK 1304*0Sstevel@tonic-gate * table) and should end with a signature word (MBB_MAGIC). 1305*0Sstevel@tonic-gate * 1306*0Sstevel@tonic-gate * Check signature at end of boot block for good value. 1307*0Sstevel@tonic-gate * If not then error with invalid request. 1308*0Sstevel@tonic-gate */ 1309*0Sstevel@tonic-gate dosp_ptr = (struct mboot *)bp->b_un.b_addr; 1310*0Sstevel@tonic-gate if (ltohs(dosp_ptr->signature) != MBB_MAGIC) { 1311*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: MBR signature error"); 1312*0Sstevel@tonic-gate rval = EINVAL; 1313*0Sstevel@tonic-gate goto out; 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate if (ldrive <= 0) { 1316*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: no logical drive specified"); 1317*0Sstevel@tonic-gate rval = EINVAL; 1318*0Sstevel@tonic-gate goto out; 1319*0Sstevel@tonic-gate } 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate if (findTheDrive(dev, ldrive, &rval, &bp, strtsectp, &sysid) == 0) 1322*0Sstevel@tonic-gate goto out; 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate /* 1325*0Sstevel@tonic-gate * Check the sysid value of the logical drive. 1326*0Sstevel@tonic-gate * Return the correct value for the type of FAT found. 1327*0Sstevel@tonic-gate * Else return a value of -1 for unknown FAT type. 1328*0Sstevel@tonic-gate */ 1329*0Sstevel@tonic-gate if ((sysid == DOS_FAT32) || (sysid == DOS_FAT32_LBA)) { 1330*0Sstevel@tonic-gate *fattypep = PCFS_FAT32 | PCFS_NOCHK; 1331*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 32-bit FAT\n"); 1332*0Sstevel@tonic-gate } else if ((sysid == DOS_SYSFAT16) || (sysid == DOS_SYSHUGE) || 1333*0Sstevel@tonic-gate (sysid == DIAGPART) || 1334*0Sstevel@tonic-gate (sysid == DOS_FAT16P_LBA) || (sysid == DOS_FAT16_LBA)) { 1335*0Sstevel@tonic-gate *fattypep = PCFS_FAT16 | PCFS_NOCHK; 1336*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 16-bit FAT\n"); 1337*0Sstevel@tonic-gate } else if (sysid == DOS_SYSFAT12) { 1338*0Sstevel@tonic-gate *fattypep = PCFS_NOCHK; 1339*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 12-bit FAT\n"); 1340*0Sstevel@tonic-gate } else if (sysid == X86BOOT) { 1341*0Sstevel@tonic-gate brelse(bp); 1342*0Sstevel@tonic-gate bp = bread(dev, *strtsectp, PC_SAFESECSIZE); 1343*0Sstevel@tonic-gate if (bp->b_flags & B_ERROR) { 1344*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_getfattype: read error\n"); 1345*0Sstevel@tonic-gate rval = EIO; 1346*0Sstevel@tonic-gate goto out; 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate bootp = (struct bootsec *)bp->b_un.b_addr; 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate /* get the sector size - may be more than 512 bytes */ 1351*0Sstevel@tonic-gate secsize = (int)ltohs(bootp->bps[0]); 1352*0Sstevel@tonic-gate /* 1353*0Sstevel@tonic-gate * Check for bogus sector size - 1354*0Sstevel@tonic-gate * fat should be at least 1 sector 1355*0Sstevel@tonic-gate */ 1356*0Sstevel@tonic-gate if (secsize < 512 || (int)ltohs(bootp->fatsec) < 1 || 1357*0Sstevel@tonic-gate bootp->nfat < 1 || bootp->spcl < 1) { 1358*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: FAT size error"); 1359*0Sstevel@tonic-gate rval = EINVAL; 1360*0Sstevel@tonic-gate goto out; 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate overhead = bootp->nfat * ltohs(bootp->fatsec); 1364*0Sstevel@tonic-gate overhead += ltohs(bootp->res_sec[0]); 1365*0Sstevel@tonic-gate overhead += (ltohs(bootp->rdirents[0]) * 1366*0Sstevel@tonic-gate sizeof (struct pcdir)) / secsize; 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate numclusters = ((ltohs(bootp->numsect[0]) ? 1369*0Sstevel@tonic-gate ltohs(bootp->numsect[0]) : ltohi(bootp->totalsec)) - 1370*0Sstevel@tonic-gate overhead) / bootp->spcl; 1371*0Sstevel@tonic-gate 1372*0Sstevel@tonic-gate if (numclusters > DOS_F12MAXC) { 1373*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 16-bit FAT BOOTPART\n"); 1374*0Sstevel@tonic-gate *fattypep = PCFS_FAT16 | PCFS_NOCHK | PCFS_BOOTPART; 1375*0Sstevel@tonic-gate } else { 1376*0Sstevel@tonic-gate PC_DPRINTF0(4, "pc_getfattype: 12-bit FAT BOOTPART\n"); 1377*0Sstevel@tonic-gate *fattypep = PCFS_NOCHK | PCFS_BOOTPART; 1378*0Sstevel@tonic-gate } 1379*0Sstevel@tonic-gate } else { 1380*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: unknown FAT type"); 1381*0Sstevel@tonic-gate rval = EINVAL; 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate /* 1385*0Sstevel@tonic-gate * Release the buffer used 1386*0Sstevel@tonic-gate */ 1387*0Sstevel@tonic-gate out: 1388*0Sstevel@tonic-gate if (bp != NULL) 1389*0Sstevel@tonic-gate brelse(bp); 1390*0Sstevel@tonic-gate (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, CRED()); 1391*0Sstevel@tonic-gate return (rval); 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gate /* 1396*0Sstevel@tonic-gate * Get the boot parameter block and file allocation table. 1397*0Sstevel@tonic-gate * If there is an old FAT, invalidate it. 1398*0Sstevel@tonic-gate */ 1399*0Sstevel@tonic-gate int 1400*0Sstevel@tonic-gate pc_getfat(struct pcfs *fsp) 1401*0Sstevel@tonic-gate { 1402*0Sstevel@tonic-gate struct vfs *vfsp = PCFSTOVFS(fsp); 1403*0Sstevel@tonic-gate struct buf *tp = 0; 1404*0Sstevel@tonic-gate struct buf *bp = 0; 1405*0Sstevel@tonic-gate uchar_t *fatp = NULL; 1406*0Sstevel@tonic-gate uchar_t *fat_changemap = NULL; 1407*0Sstevel@tonic-gate struct bootsec *bootp; 1408*0Sstevel@tonic-gate struct fat32_bootsec *f32b; 1409*0Sstevel@tonic-gate struct vnode *devvp; 1410*0Sstevel@tonic-gate int error; 1411*0Sstevel@tonic-gate int fatsize; 1412*0Sstevel@tonic-gate int fat_changemapsize; 1413*0Sstevel@tonic-gate int flags = 0; 1414*0Sstevel@tonic-gate int nfat; 1415*0Sstevel@tonic-gate int secsize; 1416*0Sstevel@tonic-gate int fatsec; 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate PC_DPRINTF0(5, "pc_getfat\n"); 1419*0Sstevel@tonic-gate devvp = fsp->pcfs_devvp; 1420*0Sstevel@tonic-gate if (fsp->pcfs_fatp) { 1421*0Sstevel@tonic-gate /* 1422*0Sstevel@tonic-gate * There is a FAT in core. 1423*0Sstevel@tonic-gate * If there are open file pcnodes or we have modified it or 1424*0Sstevel@tonic-gate * it hasn't timed out yet use the in core FAT. 1425*0Sstevel@tonic-gate * Otherwise invalidate it and get a new one 1426*0Sstevel@tonic-gate */ 1427*0Sstevel@tonic-gate #ifdef notdef 1428*0Sstevel@tonic-gate if (fsp->pcfs_frefs || 1429*0Sstevel@tonic-gate (fsp->pcfs_flags & PCFS_FATMOD) || 1430*0Sstevel@tonic-gate (gethrestime_sec() < fsp->pcfs_fattime)) { 1431*0Sstevel@tonic-gate return (0); 1432*0Sstevel@tonic-gate } else { 1433*0Sstevel@tonic-gate mutex_enter(&pcfslock); 1434*0Sstevel@tonic-gate pc_invalfat(fsp); 1435*0Sstevel@tonic-gate mutex_exit(&pcfslock); 1436*0Sstevel@tonic-gate } 1437*0Sstevel@tonic-gate #endif /* notdef */ 1438*0Sstevel@tonic-gate return (0); 1439*0Sstevel@tonic-gate } 1440*0Sstevel@tonic-gate /* 1441*0Sstevel@tonic-gate * Open block device mounted on. 1442*0Sstevel@tonic-gate */ 1443*0Sstevel@tonic-gate error = VOP_OPEN(&devvp, 1444*0Sstevel@tonic-gate (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1445*0Sstevel@tonic-gate CRED()); 1446*0Sstevel@tonic-gate if (error) { 1447*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getfat: open error=%d\n", error); 1448*0Sstevel@tonic-gate return (error); 1449*0Sstevel@tonic-gate } 1450*0Sstevel@tonic-gate /* 1451*0Sstevel@tonic-gate * Get boot parameter block and check it for validity 1452*0Sstevel@tonic-gate */ 1453*0Sstevel@tonic-gate tp = bread(fsp->pcfs_xdev, fsp->pcfs_dosstart, PC_SAFESECSIZE); 1454*0Sstevel@tonic-gate if (tp->b_flags & (B_ERROR | B_STALE)) { 1455*0Sstevel@tonic-gate PC_DPRINTF0(1, "pc_getfat: boot block error\n"); 1456*0Sstevel@tonic-gate flags = tp->b_flags & B_ERROR; 1457*0Sstevel@tonic-gate error = EIO; 1458*0Sstevel@tonic-gate goto out; 1459*0Sstevel@tonic-gate } 1460*0Sstevel@tonic-gate tp->b_flags |= B_STALE | B_AGE; 1461*0Sstevel@tonic-gate bootp = (struct bootsec *)tp->b_un.b_addr; 1462*0Sstevel@tonic-gate 1463*0Sstevel@tonic-gate /* get the sector size - may be more than 512 bytes */ 1464*0Sstevel@tonic-gate secsize = (int)ltohs(bootp->bps[0]); 1465*0Sstevel@tonic-gate /* check for bogus sector size - fat should be at least 1 sector */ 1466*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1467*0Sstevel@tonic-gate f32b = (struct fat32_bootsec *)bootp; 1468*0Sstevel@tonic-gate fatsec = ltohi(f32b->f_fatlength); 1469*0Sstevel@tonic-gate } else { 1470*0Sstevel@tonic-gate fatsec = ltohs(bootp->fatsec); 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate if (secsize < 512 || fatsec < 1 || bootp->nfat < 1) { 1473*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: FAT size error"); 1474*0Sstevel@tonic-gate error = EINVAL; 1475*0Sstevel@tonic-gate goto out; 1476*0Sstevel@tonic-gate } 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate switch (bootp->mediadesriptor) { 1479*0Sstevel@tonic-gate default: 1480*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: media-descriptor error, 0x%x", 1481*0Sstevel@tonic-gate bootp->mediadesriptor); 1482*0Sstevel@tonic-gate error = EINVAL; 1483*0Sstevel@tonic-gate goto out; 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate case MD_FIXED: 1486*0Sstevel@tonic-gate /* 1487*0Sstevel@tonic-gate * PCMCIA psuedo floppy is type MD_FIXED, 1488*0Sstevel@tonic-gate * but is accessed like a floppy 1489*0Sstevel@tonic-gate */ 1490*0Sstevel@tonic-gate if (!(fsp->pcfs_flags & PCFS_PCMCIA_NO_CIS)) { 1491*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_NOCHK; 1492*0Sstevel@tonic-gate } 1493*0Sstevel@tonic-gate /* FALLTHRU */ 1494*0Sstevel@tonic-gate case SS8SPT: 1495*0Sstevel@tonic-gate case DS8SPT: 1496*0Sstevel@tonic-gate case SS9SPT: 1497*0Sstevel@tonic-gate case DS9SPT: 1498*0Sstevel@tonic-gate case DS18SPT: 1499*0Sstevel@tonic-gate case DS9_15SPT: 1500*0Sstevel@tonic-gate fsp->pcfs_secsize = secsize; 1501*0Sstevel@tonic-gate fsp->pcfs_sdshift = secsize / DEV_BSIZE - 1; 1502*0Sstevel@tonic-gate fsp->pcfs_entps = secsize / sizeof (struct pcdir); 1503*0Sstevel@tonic-gate fsp->pcfs_spcl = (int)bootp->spcl; 1504*0Sstevel@tonic-gate fsp->pcfs_fatsec = fatsec; 1505*0Sstevel@tonic-gate fsp->pcfs_spt = (int)ltohs(bootp->spt); 1506*0Sstevel@tonic-gate fsp->pcfs_rdirsec = (int)ltohs(bootp->rdirents[0]) 1507*0Sstevel@tonic-gate * sizeof (struct pcdir) / secsize; 1508*0Sstevel@tonic-gate fsp->pcfs_clsize = fsp->pcfs_spcl * secsize; 1509*0Sstevel@tonic-gate fsp->pcfs_fatstart = fsp->pcfs_dosstart + 1510*0Sstevel@tonic-gate (daddr_t)ltohs(bootp->res_sec[0]); 1511*0Sstevel@tonic-gate fsp->pcfs_rdirstart = fsp->pcfs_fatstart + 1512*0Sstevel@tonic-gate (bootp->nfat * fsp->pcfs_fatsec); 1513*0Sstevel@tonic-gate fsp->pcfs_datastart = fsp->pcfs_rdirstart + fsp->pcfs_rdirsec; 1514*0Sstevel@tonic-gate if (IS_FAT32(fsp)) 1515*0Sstevel@tonic-gate fsp->pcfs_rdirstart = ltohi(f32b->f_rootcluster); 1516*0Sstevel@tonic-gate fsp->pcfs_ncluster = (((int)(ltohs(bootp->numsect[0]) ? 1517*0Sstevel@tonic-gate ltohs(bootp->numsect[0]) : ltohi(bootp->totalsec))) - 1518*0Sstevel@tonic-gate fsp->pcfs_datastart + fsp->pcfs_dosstart) / fsp->pcfs_spcl; 1519*0Sstevel@tonic-gate fsp->pcfs_numfat = (int)bootp->nfat; 1520*0Sstevel@tonic-gate fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 1521*0Sstevel@tonic-gate break; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate /* 1525*0Sstevel@tonic-gate * Get FAT and check it for validity 1526*0Sstevel@tonic-gate */ 1527*0Sstevel@tonic-gate fatsize = fsp->pcfs_fatsec * fsp->pcfs_secsize; 1528*0Sstevel@tonic-gate fatp = kmem_alloc(fatsize, KM_SLEEP); 1529*0Sstevel@tonic-gate error = pc_readfat(fsp, fatp, fsp->pcfs_fatstart, fatsize); 1530*0Sstevel@tonic-gate if (error) { 1531*0Sstevel@tonic-gate flags = B_ERROR; 1532*0Sstevel@tonic-gate goto out; 1533*0Sstevel@tonic-gate } 1534*0Sstevel@tonic-gate fat_changemapsize = (fatsize / fsp->pcfs_clsize) + 1; 1535*0Sstevel@tonic-gate fat_changemap = kmem_zalloc(fat_changemapsize, KM_SLEEP); 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate if (fatp[0] != bootp->mediadesriptor || 1538*0Sstevel@tonic-gate fatp[1] != 0xFF || fatp[2] != 0xFF) { 1539*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: FAT signature error"); 1540*0Sstevel@tonic-gate error = EINVAL; 1541*0Sstevel@tonic-gate goto out; 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate /* 1544*0Sstevel@tonic-gate * Checking for fatsec and number of supported clusters, should 1545*0Sstevel@tonic-gate * actually determine a FAT12/FAT media. See pc_getfattype(). 1546*0Sstevel@tonic-gate * fatp[3] != 0xFF is necessary for FAT validity. 1547*0Sstevel@tonic-gate */ 1548*0Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_FAT16) { 1549*0Sstevel@tonic-gate if ((fsp->pcfs_fatsec <= 12) && 1550*0Sstevel@tonic-gate ((fatsize * 2 / 3) >= fsp->pcfs_ncluster)) { 1551*0Sstevel@tonic-gate /* 1552*0Sstevel@tonic-gate * We have a 12-bit FAT, rather than a 16-bit FAT. 1553*0Sstevel@tonic-gate * Ignore what the fdisk table says. 1554*0Sstevel@tonic-gate */ 1555*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_getfattype: forcing 12-bit FAT\n"); 1556*0Sstevel@tonic-gate fsp->pcfs_flags &= ~PCFS_FAT16; 1557*0Sstevel@tonic-gate } else if (fatp[3] != 0xFF) { 1558*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: FAT signature error"); 1559*0Sstevel@tonic-gate error = EINVAL; 1560*0Sstevel@tonic-gate goto out; 1561*0Sstevel@tonic-gate } 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate /* 1564*0Sstevel@tonic-gate * Sanity check our FAT is large enough for the 1565*0Sstevel@tonic-gate * clusters we think we have. 1566*0Sstevel@tonic-gate */ 1567*0Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_FAT16) && 1568*0Sstevel@tonic-gate ((fatsize / 2) < fsp->pcfs_ncluster)) { 1569*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: FAT too small for number of clusters"); 1570*0Sstevel@tonic-gate error = EINVAL; 1571*0Sstevel@tonic-gate goto out; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate /* 1575*0Sstevel@tonic-gate * Get alternate FATs and check for consistency 1576*0Sstevel@tonic-gate * This is an inlined version of pc_readfat(). 1577*0Sstevel@tonic-gate * Since we're only comparing FAT and alternate FAT, 1578*0Sstevel@tonic-gate * there's no reason to let pc_readfat() copy data out 1579*0Sstevel@tonic-gate * of the buf. Instead, compare in-situ, one cluster 1580*0Sstevel@tonic-gate * at a time. 1581*0Sstevel@tonic-gate */ 1582*0Sstevel@tonic-gate for (nfat = 1; nfat < fsp->pcfs_numfat; nfat++) { 1583*0Sstevel@tonic-gate size_t startsec; 1584*0Sstevel@tonic-gate size_t off; 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gate startsec = fsp->pcfs_fatstart + nfat * fsp->pcfs_fatsec; 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate for (off = 0; off < fatsize; off += fsp->pcfs_clsize) { 1589*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, pc_dbdaddr(fsp, 1590*0Sstevel@tonic-gate startsec + 1591*0Sstevel@tonic-gate pc_cltodb(fsp, pc_lblkno(fsp, off))), 1592*0Sstevel@tonic-gate MIN(fsp->pcfs_clsize, fatsize - off)); 1593*0Sstevel@tonic-gate if (bp->b_flags & (B_ERROR | B_STALE)) { 1594*0Sstevel@tonic-gate cmn_err(CE_NOTE, 1595*0Sstevel@tonic-gate "!pcfs: alternate FAT #%d read error" 1596*0Sstevel@tonic-gate " at byte %ld", nfat, off); 1597*0Sstevel@tonic-gate flags = B_ERROR; 1598*0Sstevel@tonic-gate error = EIO; 1599*0Sstevel@tonic-gate goto out; 1600*0Sstevel@tonic-gate } 1601*0Sstevel@tonic-gate bp->b_flags |= B_STALE | B_AGE; 1602*0Sstevel@tonic-gate if (bcmp(bp->b_un.b_addr, 1603*0Sstevel@tonic-gate fatp + off, 1604*0Sstevel@tonic-gate MIN(fsp->pcfs_clsize, fatsize - off))) { 1605*0Sstevel@tonic-gate cmn_err(CE_NOTE, 1606*0Sstevel@tonic-gate "!pcfs: alternate FAT #%d corrupted" 1607*0Sstevel@tonic-gate " at byte %ld", nfat, off); 1608*0Sstevel@tonic-gate flags = B_ERROR; 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate brelse(bp); 1611*0Sstevel@tonic-gate bp = NULL; /* prevent double release */ 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate 1615*0Sstevel@tonic-gate fsp->pcfs_fatsize = fatsize; 1616*0Sstevel@tonic-gate fsp->pcfs_fatp = fatp; 1617*0Sstevel@tonic-gate fsp->pcfs_fat_changemapsize = fat_changemapsize; 1618*0Sstevel@tonic-gate fsp->pcfs_fat_changemap = fat_changemap; 1619*0Sstevel@tonic-gate fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1620*0Sstevel@tonic-gate fsp->pcfs_fatjustread = 1; 1621*0Sstevel@tonic-gate 1622*0Sstevel@tonic-gate brelse(tp); 1623*0Sstevel@tonic-gate tp = NULL; 1624*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1625*0Sstevel@tonic-gate /* get fsinfo */ 1626*0Sstevel@tonic-gate struct fat32_boot_fsinfo fsinfo_disk; 1627*0Sstevel@tonic-gate 1628*0Sstevel@tonic-gate fsp->f32fsinfo_sector = ltohs(f32b->f_infosector); 1629*0Sstevel@tonic-gate tp = bread(fsp->pcfs_xdev, 1630*0Sstevel@tonic-gate fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1631*0Sstevel@tonic-gate PC_SAFESECSIZE); 1632*0Sstevel@tonic-gate if (tp->b_flags & (B_ERROR | B_STALE)) { 1633*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: error reading fat32 fsinfo"); 1634*0Sstevel@tonic-gate flags = tp->b_flags & B_ERROR; 1635*0Sstevel@tonic-gate brelse(tp); 1636*0Sstevel@tonic-gate tp = NULL; 1637*0Sstevel@tonic-gate error = EIO; 1638*0Sstevel@tonic-gate goto out; 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate tp->b_flags |= B_STALE | B_AGE; 1641*0Sstevel@tonic-gate bcopy((void *)(tp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1642*0Sstevel@tonic-gate &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1643*0Sstevel@tonic-gate brelse(tp); 1644*0Sstevel@tonic-gate tp = NULL; 1645*0Sstevel@tonic-gate 1646*0Sstevel@tonic-gate /* translated fields */ 1647*0Sstevel@tonic-gate fsp->fsinfo_native.fs_signature = 1648*0Sstevel@tonic-gate ltohi(fsinfo_disk.fs_signature); 1649*0Sstevel@tonic-gate fsp->fsinfo_native.fs_free_clusters = 1650*0Sstevel@tonic-gate ltohi(fsinfo_disk.fs_free_clusters); 1651*0Sstevel@tonic-gate if (fsp->fsinfo_native.fs_signature != FAT32_FS_SIGN) { 1652*0Sstevel@tonic-gate cmn_err(CE_NOTE, 1653*0Sstevel@tonic-gate "!pcfs: fat32 fsinfo signature mismatch."); 1654*0Sstevel@tonic-gate error = EINVAL; 1655*0Sstevel@tonic-gate goto out; 1656*0Sstevel@tonic-gate } 1657*0Sstevel@tonic-gate } 1658*0Sstevel@tonic-gate 1659*0Sstevel@tonic-gate return (0); 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate out: 1662*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!pcfs: illegal disk format"); 1663*0Sstevel@tonic-gate if (tp) 1664*0Sstevel@tonic-gate brelse(tp); 1665*0Sstevel@tonic-gate if (bp) 1666*0Sstevel@tonic-gate brelse(bp); 1667*0Sstevel@tonic-gate if (fatp) 1668*0Sstevel@tonic-gate kmem_free(fatp, fatsize); 1669*0Sstevel@tonic-gate if (fat_changemap) 1670*0Sstevel@tonic-gate kmem_free(fat_changemap, fat_changemapsize); 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gate if (flags) { 1673*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate (void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ? 1676*0Sstevel@tonic-gate FREAD : FREAD|FWRITE, 1, (offset_t)0, CRED()); 1677*0Sstevel@tonic-gate return (error); 1678*0Sstevel@tonic-gate } 1679*0Sstevel@tonic-gate 1680*0Sstevel@tonic-gate int 1681*0Sstevel@tonic-gate pc_syncfat(struct pcfs *fsp) 1682*0Sstevel@tonic-gate { 1683*0Sstevel@tonic-gate struct buf *bp; 1684*0Sstevel@tonic-gate int nfat; 1685*0Sstevel@tonic-gate int error; 1686*0Sstevel@tonic-gate struct fat32_boot_fsinfo fsinfo_disk; 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate PC_DPRINTF0(7, "pcfs_syncfat\n"); 1689*0Sstevel@tonic-gate if ((fsp->pcfs_fatp == (uchar_t *)0) || 1690*0Sstevel@tonic-gate !(fsp->pcfs_flags & PCFS_FATMOD)) 1691*0Sstevel@tonic-gate return (0); 1692*0Sstevel@tonic-gate /* 1693*0Sstevel@tonic-gate * write out all copies of FATs 1694*0Sstevel@tonic-gate */ 1695*0Sstevel@tonic-gate fsp->pcfs_flags &= ~PCFS_FATMOD; 1696*0Sstevel@tonic-gate fsp->pcfs_fattime = gethrestime_sec() + PCFS_DISKTIMEOUT; 1697*0Sstevel@tonic-gate for (nfat = 0; nfat < fsp->pcfs_numfat; nfat++) { 1698*0Sstevel@tonic-gate error = pc_writefat(fsp, 1699*0Sstevel@tonic-gate fsp->pcfs_fatstart + nfat*fsp->pcfs_fatsec); 1700*0Sstevel@tonic-gate if (error) { 1701*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 1702*0Sstevel@tonic-gate return (EIO); 1703*0Sstevel@tonic-gate } 1704*0Sstevel@tonic-gate } 1705*0Sstevel@tonic-gate pc_clear_fatchanges(fsp); 1706*0Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_syncfat: wrote out FAT\n"); 1707*0Sstevel@tonic-gate /* write out fsinfo */ 1708*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1709*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, 1710*0Sstevel@tonic-gate fsp->pcfs_dosstart + pc_dbdaddr(fsp, fsp->f32fsinfo_sector), 1711*0Sstevel@tonic-gate PC_SAFESECSIZE); 1712*0Sstevel@tonic-gate if (bp->b_flags & (B_ERROR | B_STALE)) { 1713*0Sstevel@tonic-gate brelse(bp); 1714*0Sstevel@tonic-gate return (EIO); 1715*0Sstevel@tonic-gate } 1716*0Sstevel@tonic-gate bcopy((void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1717*0Sstevel@tonic-gate &fsinfo_disk, sizeof (struct fat32_boot_fsinfo)); 1718*0Sstevel@tonic-gate /* translate fields */ 1719*0Sstevel@tonic-gate fsinfo_disk.fs_free_clusters = 1720*0Sstevel@tonic-gate htoli(fsp->fsinfo_native.fs_free_clusters); 1721*0Sstevel@tonic-gate fsinfo_disk.fs_next_cluster = (uint32_t)FSINFO_UNKNOWN; 1722*0Sstevel@tonic-gate bcopy(&fsinfo_disk, 1723*0Sstevel@tonic-gate (void *)(bp->b_un.b_addr + FAT32_BOOT_FSINFO_OFF), 1724*0Sstevel@tonic-gate sizeof (struct fat32_boot_fsinfo)); 1725*0Sstevel@tonic-gate bwrite2(bp); 1726*0Sstevel@tonic-gate error = geterror(bp); 1727*0Sstevel@tonic-gate brelse(bp); 1728*0Sstevel@tonic-gate if (error) { 1729*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 1730*0Sstevel@tonic-gate return (EIO); 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate } 1733*0Sstevel@tonic-gate return (0); 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate void 1737*0Sstevel@tonic-gate pc_invalfat(struct pcfs *fsp) 1738*0Sstevel@tonic-gate { 1739*0Sstevel@tonic-gate struct pcfs *xfsp; 1740*0Sstevel@tonic-gate int mount_cnt = 0; 1741*0Sstevel@tonic-gate 1742*0Sstevel@tonic-gate PC_DPRINTF0(7, "pc_invalfat\n"); 1743*0Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0) 1744*0Sstevel@tonic-gate panic("pc_invalfat"); 1745*0Sstevel@tonic-gate /* 1746*0Sstevel@tonic-gate * Release FAT 1747*0Sstevel@tonic-gate */ 1748*0Sstevel@tonic-gate kmem_free(fsp->pcfs_fatp, fsp->pcfs_fatsize); 1749*0Sstevel@tonic-gate fsp->pcfs_fatp = NULL; 1750*0Sstevel@tonic-gate kmem_free(fsp->pcfs_fat_changemap, fsp->pcfs_fat_changemapsize); 1751*0Sstevel@tonic-gate fsp->pcfs_fat_changemap = NULL; 1752*0Sstevel@tonic-gate /* 1753*0Sstevel@tonic-gate * Invalidate all the blocks associated with the device. 1754*0Sstevel@tonic-gate * Not needed if stateless. 1755*0Sstevel@tonic-gate */ 1756*0Sstevel@tonic-gate for (xfsp = pc_mounttab; xfsp; xfsp = xfsp->pcfs_nxt) 1757*0Sstevel@tonic-gate if (xfsp != fsp && xfsp->pcfs_xdev == fsp->pcfs_xdev) 1758*0Sstevel@tonic-gate mount_cnt++; 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate if (!mount_cnt) 1761*0Sstevel@tonic-gate binval(fsp->pcfs_xdev); 1762*0Sstevel@tonic-gate /* 1763*0Sstevel@tonic-gate * close mounted device 1764*0Sstevel@tonic-gate */ 1765*0Sstevel@tonic-gate (void) VOP_CLOSE(fsp->pcfs_devvp, 1766*0Sstevel@tonic-gate (PCFSTOVFS(fsp)->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 1767*0Sstevel@tonic-gate 1, (offset_t)0, CRED()); 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate 1770*0Sstevel@tonic-gate void 1771*0Sstevel@tonic-gate pc_badfs(struct pcfs *fsp) 1772*0Sstevel@tonic-gate { 1773*0Sstevel@tonic-gate cmn_err(CE_WARN, "corrupted PC file system on dev %x.%x\n", 1774*0Sstevel@tonic-gate getmajor(fsp->pcfs_devvp->v_rdev), 1775*0Sstevel@tonic-gate getminor(fsp->pcfs_devvp->v_rdev)); 1776*0Sstevel@tonic-gate } 1777*0Sstevel@tonic-gate 1778*0Sstevel@tonic-gate /* 1779*0Sstevel@tonic-gate * The problem with supporting NFS on the PCFS filesystem is that there 1780*0Sstevel@tonic-gate * is no good place to keep the generation number. The only possible 1781*0Sstevel@tonic-gate * place is inside a directory entry. There are a few words that we 1782*0Sstevel@tonic-gate * don't use - they store NT & OS/2 attributes, and the creation/last access 1783*0Sstevel@tonic-gate * time of the file - but it seems wrong to use them. In addition, directory 1784*0Sstevel@tonic-gate * entries come and go. If a directory is removed completely, its directory 1785*0Sstevel@tonic-gate * blocks are freed and the generation numbers are lost. Whereas in ufs, 1786*0Sstevel@tonic-gate * inode blocks are dedicated for inodes, so the generation numbers are 1787*0Sstevel@tonic-gate * permanently kept on the disk. 1788*0Sstevel@tonic-gate */ 1789*0Sstevel@tonic-gate static int 1790*0Sstevel@tonic-gate pcfs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 1791*0Sstevel@tonic-gate { 1792*0Sstevel@tonic-gate struct pcnode *pcp; 1793*0Sstevel@tonic-gate struct pc_fid *pcfid; 1794*0Sstevel@tonic-gate struct pcfs *fsp; 1795*0Sstevel@tonic-gate struct pcdir *ep; 1796*0Sstevel@tonic-gate daddr_t eblkno; 1797*0Sstevel@tonic-gate int eoffset; 1798*0Sstevel@tonic-gate struct buf *bp; 1799*0Sstevel@tonic-gate int error; 1800*0Sstevel@tonic-gate pc_cluster32_t cn; 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp; 1803*0Sstevel@tonic-gate fsp = VFSTOPCFS(vfsp); 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0); 1806*0Sstevel@tonic-gate if (error) { 1807*0Sstevel@tonic-gate *vpp = NULL; 1808*0Sstevel@tonic-gate return (error); 1809*0Sstevel@tonic-gate } 1810*0Sstevel@tonic-gate 1811*0Sstevel@tonic-gate if (pcfid->pcfid_block == 0) { 1812*0Sstevel@tonic-gate pcp = pc_getnode(fsp, (daddr_t)0, 0, (struct pcdir *)0); 1813*0Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 1814*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 1815*0Sstevel@tonic-gate pc_unlockfs(fsp); 1816*0Sstevel@tonic-gate return (0); 1817*0Sstevel@tonic-gate } 1818*0Sstevel@tonic-gate eblkno = pcfid->pcfid_block; 1819*0Sstevel@tonic-gate eoffset = pcfid->pcfid_offset; 1820*0Sstevel@tonic-gate if ((pc_dbtocl(fsp, 1821*0Sstevel@tonic-gate eblkno - fsp->pcfs_dosstart) >= fsp->pcfs_ncluster) || 1822*0Sstevel@tonic-gate (eoffset > fsp->pcfs_clsize)) { 1823*0Sstevel@tonic-gate pc_unlockfs(fsp); 1824*0Sstevel@tonic-gate *vpp = NULL; 1825*0Sstevel@tonic-gate return (EINVAL); 1826*0Sstevel@tonic-gate } 1827*0Sstevel@tonic-gate 1828*0Sstevel@tonic-gate if (eblkno >= fsp->pcfs_datastart || (eblkno-fsp->pcfs_rdirstart) 1829*0Sstevel@tonic-gate < (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) { 1830*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, eblkno, fsp->pcfs_clsize); 1831*0Sstevel@tonic-gate } else { 1832*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, eblkno, 1833*0Sstevel@tonic-gate (int)(fsp->pcfs_datastart - eblkno) * fsp->pcfs_secsize); 1834*0Sstevel@tonic-gate } 1835*0Sstevel@tonic-gate if (bp->b_flags & (B_ERROR | B_STALE)) { 1836*0Sstevel@tonic-gate error = geterror(bp); 1837*0Sstevel@tonic-gate brelse(bp); 1838*0Sstevel@tonic-gate if (error) 1839*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 1840*0Sstevel@tonic-gate *vpp = NULL; 1841*0Sstevel@tonic-gate pc_unlockfs(fsp); 1842*0Sstevel@tonic-gate return (error); 1843*0Sstevel@tonic-gate } 1844*0Sstevel@tonic-gate ep = (struct pcdir *)(bp->b_un.b_addr + eoffset); 1845*0Sstevel@tonic-gate /* 1846*0Sstevel@tonic-gate * Ok, if this is a valid file handle that we gave out, 1847*0Sstevel@tonic-gate * then simply ensuring that the creation time matches, 1848*0Sstevel@tonic-gate * the entry has not been deleted, and it has a valid first 1849*0Sstevel@tonic-gate * character should be enough. 1850*0Sstevel@tonic-gate * 1851*0Sstevel@tonic-gate * Unfortunately, verifying that the <blkno, offset> _still_ 1852*0Sstevel@tonic-gate * refers to a directory entry is not easy, since we'd have 1853*0Sstevel@tonic-gate * to search _all_ directories starting from root to find it. 1854*0Sstevel@tonic-gate * That's a high price to pay just in case somebody is forging 1855*0Sstevel@tonic-gate * file handles. So instead we verify that as much of the 1856*0Sstevel@tonic-gate * entry is valid as we can: 1857*0Sstevel@tonic-gate * 1858*0Sstevel@tonic-gate * 1. The starting cluster is 0 (unallocated) or valid 1859*0Sstevel@tonic-gate * 2. It is not an LFN entry 1860*0Sstevel@tonic-gate * 3. It is not hidden (unless mounted as such) 1861*0Sstevel@tonic-gate * 4. It is not the label 1862*0Sstevel@tonic-gate */ 1863*0Sstevel@tonic-gate cn = pc_getstartcluster(fsp, ep); 1864*0Sstevel@tonic-gate /* 1865*0Sstevel@tonic-gate * if the starting cluster is valid, but not valid according 1866*0Sstevel@tonic-gate * to pc_validcl(), force it to be to simplify the following if. 1867*0Sstevel@tonic-gate */ 1868*0Sstevel@tonic-gate if (cn == 0) 1869*0Sstevel@tonic-gate cn = PCF_FIRSTCLUSTER; 1870*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 1871*0Sstevel@tonic-gate if (cn >= PCF_LASTCLUSTER32) 1872*0Sstevel@tonic-gate cn = PCF_FIRSTCLUSTER; 1873*0Sstevel@tonic-gate } else { 1874*0Sstevel@tonic-gate if (cn >= PCF_LASTCLUSTER) 1875*0Sstevel@tonic-gate cn = PCF_FIRSTCLUSTER; 1876*0Sstevel@tonic-gate } 1877*0Sstevel@tonic-gate if ((!pc_validcl(fsp, cn)) || 1878*0Sstevel@tonic-gate (PCDL_IS_LFN(ep)) || 1879*0Sstevel@tonic-gate (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) || 1880*0Sstevel@tonic-gate ((ep->pcd_attr & PCA_LABEL) == PCA_LABEL)) { 1881*0Sstevel@tonic-gate bp->b_flags |= B_STALE | B_AGE; 1882*0Sstevel@tonic-gate brelse(bp); 1883*0Sstevel@tonic-gate pc_unlockfs(fsp); 1884*0Sstevel@tonic-gate return (EINVAL); 1885*0Sstevel@tonic-gate } 1886*0Sstevel@tonic-gate if ((ep->pcd_crtime.pct_time == pcfid->pcfid_ctime) && 1887*0Sstevel@tonic-gate (ep->pcd_filename[0] != PCD_ERASED) && 1888*0Sstevel@tonic-gate (pc_validchar(ep->pcd_filename[0]) || 1889*0Sstevel@tonic-gate (ep->pcd_filename[0] == '.' && ep->pcd_filename[1] == '.'))) { 1890*0Sstevel@tonic-gate pcp = pc_getnode(fsp, eblkno, eoffset, ep); 1891*0Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL; 1892*0Sstevel@tonic-gate *vpp = PCTOV(pcp); 1893*0Sstevel@tonic-gate } else { 1894*0Sstevel@tonic-gate *vpp = NULL; 1895*0Sstevel@tonic-gate } 1896*0Sstevel@tonic-gate bp->b_flags |= B_STALE | B_AGE; 1897*0Sstevel@tonic-gate brelse(bp); 1898*0Sstevel@tonic-gate pc_unlockfs(fsp); 1899*0Sstevel@tonic-gate return (0); 1900*0Sstevel@tonic-gate } 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate /* 1903*0Sstevel@tonic-gate * if device is a PCMCIA psuedo floppy, return 1 1904*0Sstevel@tonic-gate * otherwise, return 0 1905*0Sstevel@tonic-gate */ 1906*0Sstevel@tonic-gate static int 1907*0Sstevel@tonic-gate pcfs_psuedo_floppy(dev_t rdev) 1908*0Sstevel@tonic-gate { 1909*0Sstevel@tonic-gate int error, err; 1910*0Sstevel@tonic-gate struct dk_cinfo info; 1911*0Sstevel@tonic-gate ldi_handle_t lh; 1912*0Sstevel@tonic-gate ldi_ident_t li; 1913*0Sstevel@tonic-gate 1914*0Sstevel@tonic-gate err = ldi_ident_from_mod(&modlinkage, &li); 1915*0Sstevel@tonic-gate if (err) { 1916*0Sstevel@tonic-gate PC_DPRINTF1(1, 1917*0Sstevel@tonic-gate "pcfs_psuedo_floppy: ldi_ident_from_mod err=%d\n", err); 1918*0Sstevel@tonic-gate return (0); 1919*0Sstevel@tonic-gate } 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate err = ldi_open_by_dev(&rdev, OTYP_CHR, FREAD, CRED(), &lh, li); 1922*0Sstevel@tonic-gate ldi_ident_release(li); 1923*0Sstevel@tonic-gate if (err) { 1924*0Sstevel@tonic-gate PC_DPRINTF1(1, 1925*0Sstevel@tonic-gate "pcfs_psuedo_floppy: ldi_open err=%d\n", err); 1926*0Sstevel@tonic-gate return (0); 1927*0Sstevel@tonic-gate } 1928*0Sstevel@tonic-gate 1929*0Sstevel@tonic-gate /* return value stored in err is purposfully ignored */ 1930*0Sstevel@tonic-gate error = ldi_ioctl(lh, DKIOCINFO, (intptr_t)&info, FKIOCTL, 1931*0Sstevel@tonic-gate CRED(), &err); 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate err = ldi_close(lh, FREAD, CRED()); 1934*0Sstevel@tonic-gate if (err != 0) { 1935*0Sstevel@tonic-gate PC_DPRINTF1(1, 1936*0Sstevel@tonic-gate "pcfs_psuedo_floppy: ldi_close err=%d\n", err); 1937*0Sstevel@tonic-gate return (0); 1938*0Sstevel@tonic-gate } 1939*0Sstevel@tonic-gate 1940*0Sstevel@tonic-gate if ((error == 0) && (info.dki_ctype == DKC_PCMCIA_MEM) && 1941*0Sstevel@tonic-gate (info.dki_flags & DKI_PCMCIA_PFD)) 1942*0Sstevel@tonic-gate return (1); 1943*0Sstevel@tonic-gate else 1944*0Sstevel@tonic-gate return (0); 1945*0Sstevel@tonic-gate } 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate /* 1948*0Sstevel@tonic-gate * Unfortunately, FAT32 fat's can be pretty big (On a 1 gig jaz drive, about 1949*0Sstevel@tonic-gate * a meg), so we can't bread() it all in at once. This routine reads a 1950*0Sstevel@tonic-gate * fat a chunk at a time. 1951*0Sstevel@tonic-gate */ 1952*0Sstevel@tonic-gate static int 1953*0Sstevel@tonic-gate pc_readfat(struct pcfs *fsp, uchar_t *fatp, daddr_t start, size_t fatsize) 1954*0Sstevel@tonic-gate { 1955*0Sstevel@tonic-gate struct buf *bp; 1956*0Sstevel@tonic-gate size_t off; 1957*0Sstevel@tonic-gate size_t readsize; 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate readsize = fsp->pcfs_clsize; 1960*0Sstevel@tonic-gate for (off = 0; off < fatsize; off += readsize, fatp += readsize) { 1961*0Sstevel@tonic-gate if (readsize > (fatsize - off)) 1962*0Sstevel@tonic-gate readsize = fatsize - off; 1963*0Sstevel@tonic-gate bp = bread(fsp->pcfs_xdev, 1964*0Sstevel@tonic-gate pc_dbdaddr(fsp, start + 1965*0Sstevel@tonic-gate pc_cltodb(fsp, pc_lblkno(fsp, off))), 1966*0Sstevel@tonic-gate readsize); 1967*0Sstevel@tonic-gate if (bp->b_flags & (B_ERROR | B_STALE)) { 1968*0Sstevel@tonic-gate brelse(bp); 1969*0Sstevel@tonic-gate return (EIO); 1970*0Sstevel@tonic-gate } 1971*0Sstevel@tonic-gate bp->b_flags |= B_STALE | B_AGE; 1972*0Sstevel@tonic-gate bcopy(bp->b_un.b_addr, fatp, readsize); 1973*0Sstevel@tonic-gate brelse(bp); 1974*0Sstevel@tonic-gate } 1975*0Sstevel@tonic-gate return (0); 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate /* 1979*0Sstevel@tonic-gate * We write the FAT out a _lot_, in order to make sure that it 1980*0Sstevel@tonic-gate * is up-to-date. But on a FAT32 system (large drive, small clusters) 1981*0Sstevel@tonic-gate * the FAT might be a couple of megabytes, and writing it all out just 1982*0Sstevel@tonic-gate * because we created or deleted a small file is painful (especially 1983*0Sstevel@tonic-gate * since we do it for each alternate FAT too). So instead, for FAT16 and 1984*0Sstevel@tonic-gate * FAT32 we only write out the bit that has changed. We don't clear 1985*0Sstevel@tonic-gate * the 'updated' fields here because the caller might be writing out 1986*0Sstevel@tonic-gate * several FATs, so the caller must use pc_clear_fatchanges() after 1987*0Sstevel@tonic-gate * all FATs have been updated. 1988*0Sstevel@tonic-gate */ 1989*0Sstevel@tonic-gate static int 1990*0Sstevel@tonic-gate pc_writefat(struct pcfs *fsp, daddr_t start) 1991*0Sstevel@tonic-gate { 1992*0Sstevel@tonic-gate struct buf *bp; 1993*0Sstevel@tonic-gate size_t off; 1994*0Sstevel@tonic-gate size_t writesize; 1995*0Sstevel@tonic-gate int error; 1996*0Sstevel@tonic-gate uchar_t *fatp = fsp->pcfs_fatp; 1997*0Sstevel@tonic-gate size_t fatsize = fsp->pcfs_fatsize; 1998*0Sstevel@tonic-gate 1999*0Sstevel@tonic-gate writesize = fsp->pcfs_clsize; 2000*0Sstevel@tonic-gate for (off = 0; off < fatsize; off += writesize, fatp += writesize) { 2001*0Sstevel@tonic-gate if (writesize > (fatsize - off)) 2002*0Sstevel@tonic-gate writesize = fatsize - off; 2003*0Sstevel@tonic-gate if (!pc_fat_is_changed(fsp, pc_lblkno(fsp, off))) { 2004*0Sstevel@tonic-gate continue; 2005*0Sstevel@tonic-gate } 2006*0Sstevel@tonic-gate bp = ngeteblk(writesize); 2007*0Sstevel@tonic-gate bp->b_edev = fsp->pcfs_xdev; 2008*0Sstevel@tonic-gate bp->b_dev = cmpdev(bp->b_edev); 2009*0Sstevel@tonic-gate bp->b_blkno = pc_dbdaddr(fsp, start + 2010*0Sstevel@tonic-gate pc_cltodb(fsp, pc_lblkno(fsp, off))); 2011*0Sstevel@tonic-gate bcopy(fatp, bp->b_un.b_addr, writesize); 2012*0Sstevel@tonic-gate bwrite2(bp); 2013*0Sstevel@tonic-gate error = geterror(bp); 2014*0Sstevel@tonic-gate brelse(bp); 2015*0Sstevel@tonic-gate if (error) { 2016*0Sstevel@tonic-gate return (error); 2017*0Sstevel@tonic-gate } 2018*0Sstevel@tonic-gate } 2019*0Sstevel@tonic-gate return (0); 2020*0Sstevel@tonic-gate } 2021*0Sstevel@tonic-gate 2022*0Sstevel@tonic-gate /* 2023*0Sstevel@tonic-gate * Mark the FAT cluster that 'cn' is stored in as modified. 2024*0Sstevel@tonic-gate */ 2025*0Sstevel@tonic-gate void 2026*0Sstevel@tonic-gate pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn) 2027*0Sstevel@tonic-gate { 2028*0Sstevel@tonic-gate pc_cluster32_t bn; 2029*0Sstevel@tonic-gate size_t size; 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate /* which fat block is the cluster number stored in? */ 2032*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 2033*0Sstevel@tonic-gate size = sizeof (pc_cluster32_t); 2034*0Sstevel@tonic-gate bn = pc_lblkno(fsp, cn * size); 2035*0Sstevel@tonic-gate fsp->pcfs_fat_changemap[bn] = 1; 2036*0Sstevel@tonic-gate } else if (IS_FAT16(fsp)) { 2037*0Sstevel@tonic-gate size = sizeof (pc_cluster16_t); 2038*0Sstevel@tonic-gate bn = pc_lblkno(fsp, cn * size); 2039*0Sstevel@tonic-gate fsp->pcfs_fat_changemap[bn] = 1; 2040*0Sstevel@tonic-gate } else { 2041*0Sstevel@tonic-gate offset_t off; 2042*0Sstevel@tonic-gate pc_cluster32_t nbn; 2043*0Sstevel@tonic-gate 2044*0Sstevel@tonic-gate ASSERT(IS_FAT12(fsp)); 2045*0Sstevel@tonic-gate off = cn + (cn >> 1); 2046*0Sstevel@tonic-gate bn = pc_lblkno(fsp, off); 2047*0Sstevel@tonic-gate fsp->pcfs_fat_changemap[bn] = 1; 2048*0Sstevel@tonic-gate /* does this field wrap into the next fat cluster? */ 2049*0Sstevel@tonic-gate nbn = pc_lblkno(fsp, off + 1); 2050*0Sstevel@tonic-gate if (nbn != bn) { 2051*0Sstevel@tonic-gate fsp->pcfs_fat_changemap[nbn] = 1; 2052*0Sstevel@tonic-gate } 2053*0Sstevel@tonic-gate } 2054*0Sstevel@tonic-gate } 2055*0Sstevel@tonic-gate 2056*0Sstevel@tonic-gate /* 2057*0Sstevel@tonic-gate * return whether the FAT cluster 'bn' is updated and needs to 2058*0Sstevel@tonic-gate * be written out. 2059*0Sstevel@tonic-gate */ 2060*0Sstevel@tonic-gate int 2061*0Sstevel@tonic-gate pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn) 2062*0Sstevel@tonic-gate { 2063*0Sstevel@tonic-gate return (fsp->pcfs_fat_changemap[bn] == 1); 2064*0Sstevel@tonic-gate } 2065