📄 sd.c
字号:
FORMG1COUNT((union scsi_cdb *)cmdblk, count); ucom->uscsi_cdblen = CDB_GROUP1; } else { FORMG0ADDR((union scsi_cdb *)cmdblk, blkno); FORMG0COUNT((union scsi_cdb *)cmdblk, count); ucom->uscsi_cdblen = CDB_GROUP0; } ucom->uscsi_bufaddr = dcom->dkc_bufaddr; ucom->uscsi_buflen = dcom->dkc_buflen; if (dcom->dkc_flags & DK_SILENT) { ucom->uscsi_flags |= USCSI_SILENT; } else if (dcom->dkc_flags & DK_DIAGNOSE) { ucom->uscsi_flags |= USCSI_DIAGNOSE; } else if (dcom->dkc_flags & DK_ISOLATE) { ucom->uscsi_flags |= USCSI_ISOLATE; } return (sdioctl_cmd(dev, (caddr_t) ucom, SD_USCSI_CDB_KERNEL));}/* * Run a command for sdioctl. */static intsdioctl_cmd(dev, data, addr_flag)dev_t dev;caddr_t data;int addr_flag;{ register struct scsi_device *devp; register struct buf *bp; register struct scsi_disk *un; int err = 0, flag, s; struct uscsi_cmd *scmd; char cmdblk[CDB_SIZE], *cdb = cmdblk; faultcode_t fault_err = -1; int blkno = 0; register caddr_t rb = 0; u_char cmd; devp = sdunits[SDUNIT(dev)]; un = UPTR; scmd = (struct uscsi_cmd *)data; if (addr_flag & SD_USCSI_CDB_KERNEL) { cdb = scmd->uscsi_cdb; } else { if (copyin((caddr_t) scmd->uscsi_cdb, (caddr_t)cdb, (u_int) scmd->uscsi_cdblen)) { return (EFAULT); } } cmd = GETCMD((union scsi_cdb *)cdb); if (DEBUGGING) { int i; printf("%s%d: cdb:", DNAME, DUNIT); for (i = 0; i != scmd->uscsi_cdblen; i++) { printf(" 0x%x", (u_char)cdb[i]); } printf("\n"); } if (scmd->uscsi_cdblen == CDB_GROUP0) { blkno = GETG0ADDR((union scsi_cdb *)cdb); } else if (scmd->uscsi_cdblen == CDB_GROUP1) { blkno = GETG1ADDR((union scsi_cdb *)cdb); } else if (scmd->uscsi_cdblen == CDB_GROUP5) { blkno = GETG5ADDR((union scsi_cdb *)cdb); } else { return (EINVAL); } flag = (scmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE; if (DEBUGGING_ALL) { printf("sdioctl_cmd: cmd= %x blk= %x buflen= 0x%x\n", cmd, blkno, scmd->uscsi_buflen); if (flag == B_WRITE && scmd->uscsi_buflen) { auto u_int i, amt = min(64, (u_int)scmd->uscsi_buflen); char bufarray[64], *buf = bufarray; if (addr_flag & SD_USCSI_BUF_KERNEL) { buf = scmd->uscsi_bufaddr; } else { if (copyin(scmd->uscsi_bufaddr, (caddr_t) buf, amt)) { return (EFAULT); } } printf("user's buf:"); for (i = 0; i < amt; i++) { printf(" 0x%x", buf[i] & 0xff); } printf("\n"); } } /* * Get buffer resources... */ bp = un->un_sbufp; s = splr(sdpri); while (bp->b_flags & B_BUSY) { bp->b_flags |= B_WANTED; (void) sleep((caddr_t) bp, PRIBIO); } bzero((caddr_t) bp, sizeof (struct buf)); bp->b_flags = B_BUSY | flag; (void) splx(s); /* * Set options. */ un->un_soptions = 0; if ((scmd->uscsi_flags & USCSI_SILENT) && !(DEBUGGING_ALL)) { un->un_soptions |= USCSI_SILENT; } if (scmd->uscsi_flags & USCSI_ISOLATE) un->un_soptions |= USCSI_ISOLATE; if (scmd->uscsi_flags & USCSI_DIAGNOSE) un->un_soptions |= USCSI_DIAGNOSE; /* * NB: * I don't know why, but changing the order of some of these things * below causes panics in kmem_free later on when ioctl(sys_generic.c) * attempt to kmem_free something it shouldn't. */ /* * Fill in the buffer with information we need * */ bp->b_forw = (struct buf *) cdb; bp->b_dev = dev; if ((bp->b_bcount = scmd->uscsi_buflen) > 0) bp->b_un.b_addr = scmd->uscsi_bufaddr; bp->b_blkno = blkno; /* * XXX: I'm not sure but that if the buffer address is in kernel * XXX: space, we might want to as_fault it in anyway (using * XXX: kas instead of u.u_procp->p_as) */ if ((scmd->uscsi_buflen) && !(addr_flag & SD_USCSI_BUF_KERNEL)) { bp->b_flags |= B_PHYS; bp->b_proc = u.u_procp; u.u_procp->p_flag |= SPHYSIO; /* * Fault lock the address range of the buffer. */ fault_err = as_fault(u.u_procp->p_as, bp->b_un.b_addr, (u_int)bp->b_bcount, F_SOFTLOCK, (bp->b_flags & B_READ) ? S_WRITE : S_READ); if (fault_err != 0) { if (FC_CODE(fault_err) == FC_OBJERR) err = FC_ERRNO(fault_err); else err = EFAULT; } else if (buscheck(bp) < 0) { err = EFAULT; } } else if ((cmd == SCMD_REASSIGN_BLOCK) && (addr_flag & SD_USCSI_CDB_KERNEL)) {#define SRBAMT sizeof (struct scsi_reassign_blk) rb = IOPBALLOC(SRBAMT); if (rb == (caddr_t) 0) { err = ENOMEM; } else { struct scsi_reassign_blk *srb; bzero(rb, SRBAMT); srb = (struct scsi_reassign_blk *) rb; srb->reserved = 0; srb->length = 4; srb->defect = bp->b_blkno; /* * The command is formatted as a Group 1 * command, although no such command exists. * Transform it back into a Group 0 command. */ FORMG1ADDR((union scsi_cdb *)cdb, 0); ((union scsi_cdb *)cdb)->scc_cmd &= ~SCMD_GROUP1; scmd->uscsi_cdblen = CDB_GROUP0; bp->b_un.b_addr = rb; bp->b_bcount = SRBAMT; } } /* * If no errors, make and run the command. */ if (err == 0) { make_sd_cmd(devp, bp, SLEEP_FUNC); if (BP_PKT(bp) && u.u_error == 0) { sdstrategy(bp); s = splr(sdpri); while ((bp->b_flags & B_DONE) == 0) { (void) sleep((caddr_t) bp, PRIBIO); } (void) splx(s); err = geterror(bp); } else if (u.u_error == 0) { err = EFAULT; } /* * get the status block */ scmd->uscsi_status = (int)SCBP_C(BP_PKT(bp)); DPRINTF_IOCTL (devp, "sdioctl_cmd status is %0x%x", scmd->uscsi_status); /* * Release the resources. */ if (fault_err == 0) { (void) as_fault(u.u_procp->p_as, bp->b_un.b_addr, (u_int)bp->b_bcount, F_SOFTUNLOCK, (bp->b_flags&B_READ)? S_WRITE: S_READ); u.u_procp->p_flag &= ~SPHYSIO; bp->b_flags &= ~B_PHYS; } scsi_resfree(BP_PKT(bp)); BP_PKT(bp) = NULL; } s = splr(sdpri); if (cmd == SCMD_REASSIGN_BLOCK && rb != (caddr_t) 0) { IOPBFREE (rb, SRBAMT); } if (bp->b_flags & B_WANTED) wakeup((caddr_t)bp); bp->b_flags &= ~(B_BUSY|B_WANTED); un->un_soptions = 0; (void) splx(s); DPRINTF_IOCTL(devp, "returning %d from ioctl", err); return (err);}/* * Unit start and Completion */static voidsdstart(devp)register struct scsi_device *devp;{ register struct buf *bp; register struct scsi_disk *un = UPTR; register struct diskhd *dp = &un->un_utab; register struct scsi_pkt *pkt; if (dp->b_forw || (bp = dp->b_actf) == NULL) { return; } if (!(pkt = BP_PKT(bp))) { make_sd_cmd(devp, bp, sdrunout); if (!(pkt = BP_PKT(bp))) { /* * XXX: actually, we should see whether or not * XXX: we could fire up a SCMD_SEEK operation * XXX: here. We may not have been able to go * XXX: because DVMA had run out, not because * XXX: we were out of command packets. */ New_state(un, SD_STATE_RWAIT); return; } else { New_state(un, SD_STATE_OPEN); } } dp->b_forw = bp; dp->b_actf = bp->b_actf; bp->b_actf = 0; /* * Try and link this command with the one that * is next, if it makes sense to do so (very rarely). */ if ((scsi_options & SCSI_OPTIONS_LINK) && (un->un_dp->options & SD_USELINKS) && dp->b_actf != NULL && bp != un->un_sbufp && un->un_wchkmap == 0 && sd_testlink(BP_PKT(bp)) == 0) { if (BP_PKT(dp->b_actf)) { sd_setlink(BP_PKT(bp)); } else { make_sd_cmd(devp, dp->b_actf, NULL_FUNC); if (BP_PKT(dp->b_actf)) { sd_setlink(BP_PKT(bp)); } } } /* * b_resid now changes from disksort key to residue storage */ bp->b_resid = pkt->pkt_resid; pkt->pkt_resid = 0; if (pkt_transport(BP_PKT(bp)) != TRAN_ACCEPT) { sdlog(devp, LOG_ERR, "transport rejected"); bp->b_flags |= B_ERROR; sddone(devp); } else if (dp->b_actf && !BP_PKT(dp->b_actf)) { make_sd_cmd(devp, dp->b_actf, NULL_FUNC); }}static intsdrunout(){ register i, s = splr(sdpri); register struct scsi_device *devp; register struct scsi_disk *un; for (i = 0; i < SD_MAXUNIT; i++) { devp = sdunits[i]; if (devp && devp->sd_present && (un = UPTR)) { if (un->un_state == SD_STATE_RWAIT) { sdstart(devp); if (un->un_state == SD_STATE_RWAIT) { (void) splx(s); return (0); } } } } (void) splx(s); return (1);}static voidsddone(devp)register struct scsi_device *devp;{ register struct buf *bp; register struct scsi_disk *un = UPTR; register struct diskhd *dp = &un->un_utab; bp = dp->b_forw; dp->b_forw = NULL; /* * Start the next one before releasing resources on this one */ if (dp->b_actf) { sdstart(devp); } if (bp != un->un_sbufp) { int flags = bp->b_flags; scsi_resfree(BP_PKT(bp)); if ((DEBUGGING_ALL && bp->b_resid) || DEBUGGING) { sdprintf(devp, "regular done: resid %d", bp->b_resid); } /* * Keep some statistics about the kinds of * transfers going to/from this device. */ if ((flags & B_ERROR) == 0) { flags = bp->b_bcount - bp->b_resid; if (flags > 0 && flags < 2<<10) flags = SDS_512_2K; else if (flags < 4<<10) flags = SDS_2K_4K; else if (flags < 8<<10) flags = SDS_4K_8K; else if (flags < 16<<10) flags = SDS_8K_16K; else if (flags < 32<<10) flags = SDS_16K_32K; else if (flags < 64<<10) flags = SDS_32K_64K; else if (flags < 128<<10) flags = SDS_64K_128K; else flags = SDS_128K_PLUS; if (bp->b_flags & B_READ) un->un_sds.sds_rbins[flags]++; else un->un_sds.sds_wbins[flags]++; if (bp->b_flags & B_PAGEIO) un->un_sds.sds_npgio++; else if ((bp->b_flags & B_PHYS) == 0) un->un_sds.sds_nsysv++; flags = bp->b_flags; }#ifdef B_KLUSTER if (flags & B_KLUSTER) { if (flags & B_ERROR) { register struct buf *xbp; sdlog(devp, LOG_ERR, "kluster error- retryings ops singly"); /* * Flip off the error bit */ bp->b_flags ^= B_ERROR; /* * Bust apart the chain */ klustbust(bp); /* * We could restore sort key for first request * (other buffer's sort keys are still valid * from first time through sdstrategy()), but * that is an overoptimization... */ bp->b_resid = 0; /* * re-sort each request back into the * queue in order to retry them singly. */ xbp = bp; while (xbp) { bp = xbp->av_forw; xbp->av_forw = xbp->av_back = NULL; (void) klustsort(dp, xbp, 0); xbp = bp; } /* * re-adjust max queue length by the decrement * at the start of the routine above. */ sdstart(devp); } else { un->un_sds.sds_kluster++; dp->b_bcount -= klustdone(bp); } } else { dp->b_bcount--; iodone(bp); }#else /* B_KLUSTER */ dp->b_bcount--; iodone(bp);#endif /* B_KLUSTER */ } else { dp->b_bcount--; DPRINTF(devp, "special done resid %d", bp->b_resid); bp->b_flags |= B_DONE; wakeup((caddr_t) bp); }}static voidmake_sd_cmd(devp, bp, func)register struct scsi_device *devp;register struct buf *bp;int (*func)();{ auto int count, com; register struct scsi_pkt *pkt; register struct scsi_disk *un = UPTR; int tval = sd_io_time; int flags = (un->un_dp->options & SD_NOPARITY)? FLAG_NOPARITY : 0; if (bp != un->un_sbufp) { struct dk_map *lp = &un->un_map[SDPART(bp->b_dev)]; long secnt; long resid; daddr_t blkno; /* * Make sure we don't run off the end of a partition. * * Put this test here so that we can adjust b_count * to accurately reflect the actual amount we are * goint to transfer. * */ secnt = (bp->b_bcount + (SECSIZE - 1)) >> SECDIV; count = MIN(secnt, lp->dkl_nblk - dkblock(bp)); if (count != secnt) { /* * We have an overrun */ resid = (secnt - count) << SECDIV; DPRINTF_ALL(devp, "overrun by %d sectors\n", secnt - count); bp->b_bcount -= resid; } else { resid = 0; } if ((pkt = BP_PKT(bp)) == (struct scsi_pkt *) 0) { pkt = scsi_resalloc(ROUTE, CDB_GROUP1, 1, (opaque_t)bp, func); if ((BP_PKT(bp) = pkt) == (struct scsi_pkt *) 0) { if (resid) { bp->b_bcount += resid; } return; } /* * We can't store the resid in b_resid because * disksort uses it for the sort key. Thus we * use pkt_resid temporarily. */ pkt->pkt_resid = resid; if (bp->b_flags & B_READ) { com = SCMD_READ; } else { com = SCMD_WRITE; } } else { if (bp->b_flags & B_READ) { com = SCMD_READ; } else if (pkt->pkt_cdbp[0] == SCMD_WRITE) { com = SCMD_VERIFY; } else { com = SCMD_WRITE; } bzero ((caddr_t) pkt->pkt_cdbp, (u_int) CDB_GROUP1); } /* * restore b_count field if it had been changed. */ if (resid) { bp->b_bcount += resid; } blkno = dkblock(bp) + (lp->dkl_cylno * un->un_g.dkg_nhead * un->un_g.dkg_nsect); /* * XXX: This needs to be reworked based upon lbasize */ if (com == SCMD_VERIFY || blkno >= (2<<20) || count > 0xff) { com |= SCMD_GROUP1; makecom_g1(pkt, devp, flags, com, (int) blkno, count); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -