📄 sd.c
字号:
* This is a totally bogus geometry- really need to do a mode * sense. */ label = 0; bzero((caddr_t) &un->un_g, sizeof (struct dk_geom)); un->un_g.dkg_pcyl = un->un_capacity >> 5; un->un_g.dkg_ncyl = un->un_g.dkg_pcyl - 2; un->un_g.dkg_acyl = 2; un->un_g.dkg_nhead = 1; un->un_g.dkg_nsect = 32; un->un_g.dkg_intrlv = 1; un->un_g.dkg_rpm = 3000; bzero((caddr_t)un->un_map, NDKMAP * (sizeof (struct dk_map))); un->un_map['c'-'a'].dkl_cylno = 0; un->un_map['c'-'a'].dkl_nblk = un->un_capacity; inq_fill(devp->sd_inq->inq_vid, 8, labelstring); printf("sd%d: <%s %d blocks>\n", unit, labelstring, un->un_capacity); } if (un->un_state == SD_STATE_NIL) { New_state(un, SD_STATE_CLOSED); /* * print out a message indicating who and what we are * if the geometry is valid, print the label string, * else print vendor and product info, if available */ if (un->un_gvalid && label) { printf("sd%d: <%s>\n", unit, label); } else { inq_fill(devp->sd_inq->inq_vid, 8, labelstring); inq_fill(devp->sd_inq->inq_pid, 16, &labelstring[64]); printf("sd%d: Vendor '%s', product '%s'", unit, labelstring, &labelstring[64]); if (un->un_capacity > 0) { printf(", %d %d byte blocks\n", un->un_capacity, un->un_lbasize); } else printf(", (unknown capacity)\n"); } }}/* * Check the label for righteousity, and snarf yummos from validated label. * Marks the geometyr of the unit as being valid. */static voidsd_uselabel(devp, l)struct scsi_device *devp;struct dk_label *l;{ static char *geom = "Label says %d blocks, Drive says %d blocks"; static char *badlab = "corrupt label - %s"; short *sp, sum, count; struct scsi_disk *un = UPTR; long capacity; /* * Check magic number of the label */ if (l->dkl_magic != DKL_MAGIC) { if (UPTR->un_state == SD_STATE_NIL) sdlog(devp, LOG_ERR, badlab, "wrong magic number"); return; } /* * Check the checksum of the label */ sp = (short *)l; sum = 0; count = sizeof (struct dk_label) / sizeof (short); while (count--) { sum ^= *sp++; } if (sum) { if (un->un_state == SD_STATE_NIL) sdlog(devp, LOG_ERR, badlab, "label checksum failed"); return; } /* * Fill in disk geometry from label. */ un->un_g.dkg_ncyl = l->dkl_ncyl; un->un_g.dkg_acyl = l->dkl_acyl; un->un_g.dkg_bcyl = 0; un->un_g.dkg_nhead = l->dkl_nhead; un->un_g.dkg_bhead = l->dkl_bhead; un->un_g.dkg_nsect = l->dkl_nsect; un->un_g.dkg_gap1 = l->dkl_gap1; un->un_g.dkg_gap2 = l->dkl_gap2; un->un_g.dkg_intrlv = l->dkl_intrlv; un->un_g.dkg_pcyl = l->dkl_pcyl; un->un_g.dkg_rpm = l->dkl_rpm; /* * If labels don't have pcyl in them, make a guess at it. * The right thing, of course, to do, is to do a MODE SENSE * on the Rigid Disk Geometry mode page and check the * information with that. Won't work for non-CCS though. */ if (un->un_g.dkg_pcyl == 0) un->un_g.dkg_pcyl = un->un_g.dkg_ncyl + un->un_g.dkg_acyl; /* * Fill in partition table. */ bcopy((caddr_t) l->dkl_map, (caddr_t) un->un_map, NDKMAP * sizeof (struct dk_map)); /* * dk instrumentation */#ifdef OPENPROMS if ((u_char) un->un_dkn == (u_char) -1) { int i = newdk("sd", DUNIT); if (i >= 0) { un->un_dkn = i; i = un->un_g.dkg_intrlv; if (i <= 0 || i >= un->un_g.dkg_nsect) { i = 1; } dk_bps[un->un_dkn] = (SECSIZE * 60 * un->un_g.dkg_nsect) / i; } }#else OPENPROMS if ((u_char) un->un_dkn == (u_char) -1 && devp->sd_dev->md_dk == 1 && dkn < DK_NDRIVE) { int intrlv = un->un_g.dkg_intrlv; if (intrlv <= 0 || intrlv >= un->un_g.dkg_nsect) { intrlv = 1; } devp->sd_dev->md_dk = un->un_dkn = dkn++; dk_bps[un->un_dkn] = (SECSIZE * 60 * un->un_g.dkg_nsect) / intrlv; } else { devp->sd_dev->md_dk = -1; }#endif OPENPROMS un->un_gvalid = 1; /* "it's here..." */ capacity = un->un_g.dkg_ncyl * un->un_g.dkg_nhead * un->un_g.dkg_nsect; if (un->un_g.dkg_acyl) capacity += (un->un_g.dkg_nhead * un->un_g.dkg_nsect); if (un->un_capacity > 0) { if (capacity > un->un_capacity && un->un_state == SD_STATE_NIL) { sdlog(devp, LOG_ERR, badlab, "bad geometry"); sdlog(devp, LOG_ERR, geom, capacity, un->un_capacity); un->un_gvalid = 0; /* "No it's not!.." */ } else if (DEBUGGING_ALL) { sdlog(devp, LOG_INFO, geom, capacity, un->un_capacity); } } else { /* * We have a situation where the target didn't give us a * good 'read capacity' command answer, yet there appears * to be a valid label. In this case, we'll * fake the capacity. */ un->un_capacity = capacity; }}/* * Unix Entry Points */intsdopen(dev, flag)dev_t dev;int flag;{ register struct scsi_device *devp; register struct scsi_disk *un; register int unit, s; if ((unit = SDUNIT(dev)) >= SD_MAXUNIT) { return (ENXIO); } if (!(devp = sdunits[unit])) { struct scsi_address *sa = sdsvdaddr[unit]; if (sa) { if (scsi_add_device(sa, &DRIVER, "sd", unit) == 0) { return (ENXIO); } devp = sdunits[unit]; if (!devp) { return (ENXIO); } (void) kmem_free((caddr_t) sa, sizeof (*sa)); sdsvdaddr[unit] = (struct scsi_address *) 0; } else { return (ENXIO); } } else if (!devp->sd_present) { s = splr(sdpri); if (sd_findslave(devp, 1) > 0) { printf("sd%d at %s%d target %d lun %d\n", unit, CNAME, CUNIT, Tgt(devp), Lun(devp)); sd_doattach(devp, SLEEP_FUNC); } else { (void) splx(s); return (ENXIO); } (void) splx(s); } un = UPTR; if (un->un_gvalid == 0) { s = splr(sdpri); sd_doattach(devp, SLEEP_FUNC); (void) splx(s); } /* * no, don't put an else here: sdattach may validate the geometry.... */ if (un->un_gvalid == 0 || un->un_map[SDPART(dev)].dkl_nblk <= 0) { /* * Are we opening this for format(8)? */ if ((flag & (FNDELAY|FNBIO)) == 0 || !SD_ISCDEV(dev)) { return (ENXIO); } } if (un->un_state == SD_STATE_DETACHING) { if (sd_unit_ready(dev) == 0) { return (ENXIO); } /* * disk now back on line... */ New_state(un, SD_STATE_OPENING); sdlog(devp, LOG_INFO, diskokay); } else if (un->un_state == SD_STATE_CLOSED) { New_state(un, SD_STATE_OPENING); if (sd_unit_ready(dev) == 0) { sd_offline(devp, 1); return (ENXIO); } /* * If this is a removable media device, try and send * a PREVENT MEDIA REMOVAL command, but don't get upset * if it fails. */ if (devp->sd_inq->inq_rmb) { sd_lock_unlock(dev, 1); } } New_state(un, SD_STATE_OPEN); SD_SET_OMAP(un, &dev); return (0);}intsdclose(dev)dev_t dev;{ register struct scsi_device *devp; register struct scsi_disk *un; int unit; if ((unit = SDUNIT(dev)) >= SD_MAXUNIT) { return (ENXIO); } else if (!(devp = sdunits[unit]) || !devp->sd_present) { return (ENXIO); } else if (!(un = UPTR) || un->un_state < SD_STATE_OPEN) { return (ENXIO); } DPRINTF(devp, "last close on dev %d.%d", major(dev), minor(dev)); SD_CLR_OMAP(un, &dev); if (un->un_omap == 0) { if (un->un_state == SD_STATE_DETACHING) { sd_offline(devp, 1); } else { New_state(un, SD_STATE_CLOSED); /* * If this is a removable media device, try and send * an ALLOW MEDIA REMOVAL command, but don't get upset * if it fails. * * For now, if it is a removable media device, * invalidate the geometry. * * XXX: Later investigate whether or not it * XXX: would be a good idea to invalidate * XXX: the geometry for all devices. */ if (devp->sd_inq->inq_rmb) { sd_lock_unlock(dev, 0); un->un_gvalid = 0; } } } return (0);}static voidsd_offline(devp, bechatty)register struct scsi_device *devp;int bechatty;{ register struct scsi_disk *un = UPTR; if (bechatty) sdlog(devp, LOG_WARNING, "offline");#ifdef OPENPROMS (void) remdk((int) un->un_dkn);#endif /* OPENPROMS */ free_pktiopb(un->un_rqs, (caddr_t)devp->sd_sense, SENSE_LENGTH); (void) kmem_free((caddr_t) un->un_sbufp, (unsigned) (sizeof (struct buf))); (void) kmem_free((caddr_t) un, (unsigned) (sizeof (struct scsi_disk))); devp->sd_private = (opaque_t) 0; IOPBFREE (devp->sd_inq, SUN_INQSIZE); devp->sd_inq = (struct scsi_inquiry *) 0; devp->sd_sense = 0; devp->sd_present = 0;}intsdsize(dev)dev_t dev;{ struct scsi_device *devp; int unit; if ((unit = SDUNIT(dev)) >= SD_MAXUNIT) { return (-1); } else if (!(devp = sdunits[unit]) || !devp->sd_present || !UPTR->un_gvalid) { return (-1); } return ((int)UPTR->un_map[SDPART(dev)].dkl_nblk);}/* * These routines perform raw i/o operations. */sdread(dev, uio)dev_t dev;struct uio *uio;{ return (sdrw(dev, uio, B_READ));}sdwrite(dev, uio)dev_t dev;struct uio *uio;{ return (sdrw(dev, uio, B_WRITE));}static voidsdmin(bp)struct buf *bp;{ if (bp->b_bcount > sdmaxphys) bp->b_bcount = sdmaxphys;}static intsdrw(dev, uio, flag)dev_t dev;struct uio *uio;int flag;{ struct scsi_device *devp; register int unit; if ((unit = SDUNIT(dev)) >= SD_MAXUNIT) { return (ENXIO); } else if (!(devp = sdunits[unit]) || !devp->sd_present || !UPTR->un_gvalid) { return (ENXIO); } else if ((uio->uio_fmode & FSETBLK) == 0 && (uio->uio_offset & (DEV_BSIZE - 1))) { DPRINTF(devp, "file offset not modulo %d", DEV_BSIZE); return (EINVAL); } else if (uio->uio_iov->iov_len & (DEV_BSIZE - 1)) { DPRINTF(devp, "block length not modulo %d", DEV_BSIZE); return (EINVAL); } return (physio(sdstrategy, (struct buf *) 0, dev, flag, sdmin, uio));}/* * strategy routine */int (*sdstrategy_tstpoint)();intsdstrategy(bp)register struct buf *bp;{ register struct scsi_device *devp; register struct scsi_disk *un; register struct diskhd *dp; register s; if (sdstrategy_tstpoint != NULL) { if ((*sdstrategy_tstpoint)(bp)) { return; } } devp = sdunits[SDUNIT(bp->b_dev)]; if (!devp || !devp->sd_present || !(un = UPTR) || un->un_state == SD_STATE_DUMPING) {nothere: bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; bp->b_error = ENXIO; iodone(bp); return; } if (bp != un->un_sbufp && un->un_state == SD_STATE_DETACHING) { if (sd_unit_ready(bp->b_dev) == 0) { goto nothere; } /* * disk now back on line... */ New_state(un, SD_STATE_OPEN); sdlog(devp, LOG_INFO, diskokay); } bp->b_flags &= ~(B_DONE|B_ERROR); bp->av_forw = 0; dp = &un->un_utab; if (bp != un->un_sbufp) { if (un->un_gvalid == 0) { sdlog(devp, LOG_ERR, "i/o to invalid geometry"); bp->b_flags |= B_ERROR; } else { struct dk_map *lp = &un->un_map[SDPART(bp->b_dev)]; register daddr_t bn = dkblock(bp); /* * Use s to note whether we are * either done and/or in error. */ s = 0; if (bn < 0) { s = -1; } else if (bn >= lp->dkl_nblk) { /* * if bn == lp->dkl_nblk, * Not an error, resid == count */ if (bn > lp->dkl_nblk) { s = -1; } else { s = 1; } } else if (bp->b_bcount & (SECSIZE-1)) { /* * This should really be: * * ... if (bp->b_bcount & (un->un_lbasize-1)) * */ s = -1; } else { /* * sort by absolute block number. * note that b_resid is used to store * sort key and to return the transfer * resid. */ bp->b_resid = bn + lp->dkl_cylno * un->un_g.dkg_nhead * un->un_g.dkg_nsect; /* * zero out av_back - this will be a signal * to sdstart to go and fetch the resources */ BP_PKT(bp) = 0; } /* * Check to see whether or not we are done (with * or without errors), then reuse s for tmp var * calculations for stats gathering. */ if (s != 0) { bp->b_resid = bp->b_bcount; if (s < 0) { bp->b_flags |= B_ERROR; } else { iodone(bp); } } } } else { /* * For internal cmds, we just zero out the sort key */ bp->b_resid = 0; } if ((s = (bp->b_flags & (B_DONE|B_ERROR))) == 0) { s = splr(sdpri); /* * We are doing it a bit non-standard. That is, the * head of the b_actf chain is *not* the active command- * it is just the head of the wait queue. The reason * we do this is that the head of the b_actf chain is * guaranteed to not be moved by disksort(), so that * our actual current active command (pointed to by * b_forw) and the head of the wait queue (b_actf) can * have resources granted without it getting lost in * the queue at some later point (where we would have * to go and look for it). */#ifdef B_KLUSTER if (klustsort(dp, bp, sdmaxphys)) { bp = dp->b_actf; if (BP_PKT(bp) && (bp->b_flags & B_KLUSTER)) { scsi_resfree(BP_PKT(bp)); BP_PKT(bp) = NULL; } }#else /* B_KLUSTER */ disksort(dp, bp);#endif /* B_KLUSTER */ if ((++dp->b_bcount) > un->un_sds.sds_hiqlen) un->un_sds.sds_hiqlen = dp->b_bcount; if (dp->b_forw == NULL) { /* this device inactive? */ sdstart(devp); } else if (BP_PKT(dp->b_actf) == 0) { /* * try and map this one */ make_sd_cmd(devp, dp->b_actf, NULL_FUNC); } (void) splx(s); } else if ((s & B_DONE) == 0) { iodone(bp); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -