int fdopen(dev_t dev, int flags, int mode, struct lwp *l) { struct fd_softc *fd; const struct fd_type *type; fd = device_lookup_private(&fd_cd, FDUNIT(dev)); if (fd == NULL) return (ENXIO); type = fd_dev_to_type(fd, dev); if (type == NULL) return ENXIO; if ((fd->sc_flags & FD_OPEN) != 0 && memcmp(fd->sc_type, type, sizeof(*type))) return EBUSY; fd->sc_type_copy = *type; fd->sc_type = &fd->sc_type_copy; fd->sc_cylin = -1; fd->sc_flags |= FD_OPEN; fd_set_properties(fd); return 0; }
int fdclose(dev_t dev, int flags, int mode, struct lwp *l) { struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); fd->sc_flags &= ~FD_OPEN; fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); return 0; }
int fdopen(dev_t dev, int flags, int fmt, struct proc *p) { int unit, pmask; struct fd_softc *fd; struct fd_type *type; unit = FDUNIT(dev); if (unit >= fd_cd.cd_ndevs) return ENXIO; fd = fd_cd.cd_devs[unit]; if (fd == 0) return ENXIO; type = fd_dev_to_type(fd, dev); if (type == NULL) return ENXIO; if ((fd->sc_flags & FD_OPEN) != 0 && fd->sc_type != type) return EBUSY; fd->sc_type = type; fd->sc_cylin = -1; fd->sc_flags |= FD_OPEN; /* * Only update the disklabel if we're not open anywhere else. */ if (fd->sc_dk.dk_openmask == 0) fdgetdisklabel(dev, fd, fd->sc_dk.dk_label, 0); pmask = (1 << FDPART(dev)); switch (fmt) { case S_IFCHR: fd->sc_dk.dk_copenmask |= pmask; break; case S_IFBLK: fd->sc_dk.dk_bopenmask |= pmask; break; } fd->sc_dk.dk_openmask = fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; return 0; }
int fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l) { int rv = 0; struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); struct fd_type *type = fd->sc_type; struct buf *bp; /* set up a buffer header for fdstrategy() */ bp = getiobuf(NULL, false); if (bp == NULL) return ENOBUFS; bp->b_cflags = BC_BUSY; bp->b_flags = B_PHYS | B_FORMAT; bp->b_proc = l->l_proc; bp->b_dev = dev; /* * calculate a fake blkno, so fdstrategy() would initiate a * seek to the requested cylinder */ bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; bp->b_data = (void *)finfo; #ifdef DEBUG printf("fdformat: blkno %" PRIx64 " count %x\n", bp->b_blkno, bp->b_bcount); #endif /* now do the format */ fdstrategy(bp); /* ...and wait for it to complete */ rv = biowait(bp); putiobuf(bp); return rv; }
int fdformat(dev_t dev, struct fd_formb *finfo, struct proc *p) { int rv = 0; struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; struct fd_type *type = fd->sc_type; struct buf *bp; int fd_bsize = FD_BSIZE(fd); /* set up a buffer header for fdstrategy() */ bp = malloc(sizeof(*bp), M_TEMP, M_NOWAIT | M_ZERO); if (bp == NULL) return ENOBUFS; bp->b_flags = B_BUSY | B_PHYS | B_FORMAT | B_RAW; bp->b_proc = p; bp->b_dev = dev; /* * calculate a fake blkno, so fdstrategy() would initiate a * seek to the requested cylinder */ bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE; bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; bp->b_data = (caddr_t)finfo; #ifdef DEBUG printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount); #endif /* now do the format */ fdstrategy(bp); /* ...and wait for it to complete */ rv = biowait(bp); free(bp, M_TEMP); return (rv); }
int fdclose(dev_t dev, int flags, int fmt, struct proc *p) { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; int pmask = (1 << FDPART(dev)); fd->sc_flags &= ~FD_OPEN; fd->sc_opts &= ~FDOPT_NORETRY; switch (fmt) { case S_IFCHR: fd->sc_dk.dk_copenmask &= ~pmask; break; case S_IFBLK: fd->sc_dk.dk_bopenmask &= ~pmask; break; } fd->sc_dk.dk_openmask = fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; return (0); }
void fdstrategy(struct buf *bp) { struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev)); struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev)); int sz; /* Valid unit, controller, and request? */ if (bp->b_blkno < 0 || ((bp->b_bcount % FDC_BSIZE) != 0 && (bp->b_flags & B_FORMAT) == 0)) { bp->b_error = EINVAL; goto done; } /* If it's a null transfer, return immediately. */ if (bp->b_bcount == 0) goto done; sz = howmany(bp->b_bcount, FDC_BSIZE); if (bp->b_blkno + sz > fd->sc_type->size) { sz = fd->sc_type->size - bp->b_blkno; if (sz == 0) { /* If exactly at end of disk, return EOF. */ goto done; } if (sz < 0) { /* If past end of disk, return EINVAL. */ bp->b_error = EINVAL; goto done; } /* Otherwise, truncate request. */ bp->b_bcount = sz << DEV_BSHIFT; } bp->b_rawblkno = bp->b_blkno; bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl; #ifdef FD_DEBUG printf("fdstrategy: b_blkno %llu b_bcount %d blkno %llu cylin %d " "sz %d\n", (unsigned long long)bp->b_blkno, bp->b_bcount, (unsigned long long)fd->sc_blkno, bp->b_cylinder, sz); #endif /* Queue transfer on drive, activate drive and controller if idle. */ mutex_enter(&fdc->sc_mtx); BUFQ_PUT(fd->sc_q, bp); callout_stop(&fd->sc_motoroff_ch); /* a good idea */ if (fd->sc_active == 0) fdstart(fd); #ifdef DIAGNOSTIC else { if (fdc->sc_state == DEVIDLE) { printf("fdstrategy: controller inactive\n"); fdcstart(fdc); } } #endif mutex_exit(&fdc->sc_mtx); return; done: /* Toss transfer; we're done early. */ bp->b_resid = bp->b_bcount; biodone(bp); }
int fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev)); struct fdformat_parms *form_parms; struct fdformat_cmd *form_cmd; struct ne7_fd_formb *fd_formb; struct disklabel buffer; int error; unsigned int scratch; int il[FD_MAX_NSEC + 1]; int i, j; #ifdef __HAVE_OLD_DISKLABEL struct disklabel newlabel; #endif switch (cmd) { case DIOCGDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCGDINFO: #endif memset(&buffer, 0, sizeof(buffer)); buffer.d_secpercyl = fd->sc_type->seccyl; buffer.d_type = DTYPE_FLOPPY; buffer.d_secsize = FDC_BSIZE; if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL) return EINVAL; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCGDINFO) { if (buffer.d_npartitions > OLDMAXPARTITIONS) return ENOTTY; memcpy(addr, &buffer, sizeof (struct olddisklabel)); } else #endif *(struct disklabel *)addr = buffer; return 0; case DIOCWLABEL: if ((flag & FWRITE) == 0) return EBADF; /* XXX do something */ return 0; case DIOCWDINFO: #ifdef __HAVE_OLD_DISKLABEL case ODIOCWDINFO: #endif { struct disklabel *lp; if ((flag & FWRITE) == 0) return EBADF; #ifdef __HAVE_OLD_DISKLABEL if (cmd == ODIOCWDINFO) { memset(&newlabel, 0, sizeof newlabel); memcpy(&newlabel, addr, sizeof (struct olddisklabel)); lp = &newlabel; } else #endif lp = (struct disklabel *)addr; error = setdisklabel(&buffer, lp, 0, NULL); if (error) return error; error = writedisklabel(dev, fdstrategy, &buffer, NULL); return error; } case FDIOCGETFORMAT: form_parms = (struct fdformat_parms *)addr; form_parms->fdformat_version = FDFORMAT_VERSION; form_parms->nbps = 128 * (1 << fd->sc_type->secsize); form_parms->ncyl = fd->sc_type->cyls; form_parms->nspt = fd->sc_type->sectrac; form_parms->ntrk = fd->sc_type->heads; form_parms->stepspercyl = fd->sc_type->step; form_parms->gaplen = fd->sc_type->gap2; form_parms->fillbyte = fd->sc_type->fillbyte; form_parms->interleave = fd->sc_type->interleave; switch (fd->sc_type->rate) { case FDC_500KBPS: form_parms->xfer_rate = 500 * 1024; break; case FDC_300KBPS: form_parms->xfer_rate = 300 * 1024; break; case FDC_250KBPS: form_parms->xfer_rate = 250 * 1024; break; default: return EINVAL; } return 0; case FDIOCSETFORMAT: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_parms = (struct fdformat_parms *)addr; if (form_parms->fdformat_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ scratch = form_parms->nbps >> 7; if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 || scratch & ~(1 << (ffs(scratch)-1))) /* not a power-of-two multiple of 128 */ return EINVAL; switch (form_parms->xfer_rate) { case 500 * 1024: fd->sc_type->rate = FDC_500KBPS; break; case 300 * 1024: fd->sc_type->rate = FDC_300KBPS; break; case 250 * 1024: fd->sc_type->rate = FDC_250KBPS; break; default: return EINVAL; } if (form_parms->nspt > FD_MAX_NSEC || form_parms->fillbyte > 0xff || form_parms->interleave > 0xff) return EINVAL; fd->sc_type->sectrac = form_parms->nspt; if (form_parms->ntrk != 2 && form_parms->ntrk != 1) return EINVAL; fd->sc_type->heads = form_parms->ntrk; fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk; fd->sc_type->secsize = ffs(scratch)-1; fd->sc_type->gap2 = form_parms->gaplen; fd->sc_type->cyls = form_parms->ncyl; fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl * form_parms->nbps / DEV_BSIZE; fd->sc_type->step = form_parms->stepspercyl; fd->sc_type->fillbyte = form_parms->fillbyte; fd->sc_type->interleave = form_parms->interleave; return 0; case FDIOCFORMAT_TRACK: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ form_cmd = (struct fdformat_cmd *)addr; if (form_cmd->formatcmd_version != FDFORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ if (form_cmd->head >= fd->sc_type->heads || form_cmd->cylinder >= fd->sc_type->cyls) { return EINVAL; } fd_formb = malloc(sizeof(struct ne7_fd_formb), M_TEMP, M_NOWAIT); if (fd_formb == 0) return ENOMEM; fd_formb->head = form_cmd->head; fd_formb->cyl = form_cmd->cylinder; fd_formb->transfer_rate = fd->sc_type->rate; fd_formb->fd_formb_secshift = fd->sc_type->secsize; fd_formb->fd_formb_nsecs = fd->sc_type->sectrac; fd_formb->fd_formb_gaplen = fd->sc_type->gap2; fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte; memset(il, 0, sizeof il); for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) { while (il[(j%fd_formb->fd_formb_nsecs)+1]) j++; il[(j%fd_formb->fd_formb_nsecs)+1] = i; j += fd->sc_type->interleave; } for (i = 0; i < fd_formb->fd_formb_nsecs; i++) { fd_formb->fd_formb_cylno(i) = form_cmd->cylinder; fd_formb->fd_formb_headno(i) = form_cmd->head; fd_formb->fd_formb_secno(i) = il[i+1]; fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize; } error = fdformat(dev, fd_formb, l); free(fd_formb, M_TEMP); return error; case FDIOCGETOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FDIOCSETOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }
int fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; struct disklabel *lp; int error; switch (cmd) { case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) return EIO; return (0); case DIOCRLDINFO: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); fdgetdisklabel(dev, fd, lp, 0); bcopy(lp, fd->sc_dk.dk_label, sizeof(*lp)); free(lp, M_TEMP); return 0; case DIOCGPDINFO: fdgetdisklabel(dev, fd, (struct disklabel *)addr, 1); return 0; case DIOCGDINFO: *(struct disklabel *)addr = *(fd->sc_dk.dk_label); return 0; case DIOCGPART: ((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label; ((struct partinfo *)addr)->part = &fd->sc_dk.dk_label->d_partitions[FDPART(dev)]; return 0; case DIOCWDINFO: case DIOCSDINFO: if ((flag & FWRITE) == 0) return EBADF; error = setdisklabel(fd->sc_dk.dk_label, (struct disklabel *)addr, 0); if (error == 0) { if (cmd == DIOCWDINFO) error = writedisklabel(DISKLABELDEV(dev), fdstrategy, fd->sc_dk.dk_label); } return error; case FD_FORM: if((flag & FWRITE) == 0) return EBADF; /* must be opened for writing */ else if(((struct fd_formb *)addr)->format_version != FD_FORMAT_VERSION) return EINVAL; /* wrong version of formatting prog */ else return fdformat(dev, (struct fd_formb *)addr, p); break; case FD_GTYPE: /* get drive type */ *(struct fd_type *)addr = *fd->sc_type; return 0; case FD_GOPTS: /* get drive options */ *(int *)addr = fd->sc_opts; return 0; case FD_SOPTS: /* set drive options */ fd->sc_opts = *(int *)addr; return 0; default: return ENOTTY; } #ifdef DIAGNOSTIC panic("fdioctl: impossible"); #endif }
void fdstrategy(struct buf *bp) { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)]; int sz; int s; int fd_bsize = FD_BSIZE(fd); int bf = fd_bsize / DEV_BSIZE; /* Valid unit, controller, and request? */ if (bp->b_blkno < 0 || (((bp->b_blkno % bf) != 0 || (bp->b_bcount % fd_bsize) != 0) && (bp->b_flags & B_FORMAT) == 0)) { bp->b_error = EINVAL; goto bad; } /* If it's a null transfer, return immediately. */ if (bp->b_bcount == 0) goto done; sz = howmany(bp->b_bcount, DEV_BSIZE); if (bp->b_blkno + sz > fd->sc_type->size * bf) { sz = fd->sc_type->size * bf - bp->b_blkno; if (sz == 0) /* If exactly at end of disk, return EOF. */ goto done; if (sz < 0) { /* If past end of disk, return EINVAL. */ bp->b_error = EINVAL; goto bad; } /* Otherwise, truncate request. */ bp->b_bcount = sz << DEV_BSHIFT; } bp->b_resid = bp->b_bcount; #ifdef FD_DEBUG printf("fdstrategy: b_blkno %lld b_bcount %d blkno %lld sz %d\n", (long long)bp->b_blkno, bp->b_bcount, (long long)fd->sc_blkno, sz); #endif /* Queue I/O */ bufq_queue(&fd->sc_bufq, bp); /* Queue transfer on drive, activate drive and controller if idle. */ s = splbio(); timeout_del(&fd->fd_motor_off_to); /* a good idea */ if (fd->sc_bp == NULL) fdstart(fd); #ifdef DIAGNOSTIC else { struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; if (fdc->sc_state == DEVIDLE) { printf("fdstrategy: controller inactive\n"); fdcstart(fdc); } } #endif splx(s); return; bad: bp->b_flags |= B_ERROR; done: /* Toss transfer; we're done early. */ bp->b_resid = bp->b_bcount; s = splbio(); biodone(bp); splx(s); }