📄 sr.c
字号:
/*^L*//* * * Local Functions * *//* * Run a command for srioctl. */static intsrioctl_cmd(dev, data, addr_flag)dev_t dev;caddr_t data;int addr_flag;{ register struct scsi_device *devp; register struct buf *bp, *rbp; register struct scsi_disk *un; int err = 0, flag, s; int err1; struct uscsi_cmd *scmd; char cmdblk[12], *cdb = cmdblk; faultcode_t fault_err = -1; int blkno = 0; /* * Checking for sanity done in srioctl */ devp = srunits[SRUNIT(dev)]; un = UPTR; scmd = (struct uscsi_cmd *)data; if (addr_flag & SR_USCSI_CDB_KERNEL) { cdb = scmd->uscsi_cdb; } else { if (copyin(scmd->uscsi_cdb, (caddr_t)cdb, (u_int)scmd->uscsi_cdblen)) { return (EINVAL); } } 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"); } switch (cdb_cmd(cdb)) { case SCMD_READ: blkno = cdb0_blkno(cdb);/* if (addr_flag & SR_MODE2) { if (scmd->uscsi_buflen & (CDROM_MODE2_SIZE - 1)) { return (EINVAL); } } else {*/ if (!(addr_flag & SR_MODE2)) { if (scmd->uscsi_buflen & (SECSIZE-1)) { return (EINVAL); } } /* FALLTHRU */ default: flag = (scmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE; break; } if (DEBUGGING_ALL) { printf("srioctl_cmd: cmd= %x blk= %x buflen= 0x%x\n", cdb_cmd(cdb), 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 & SR_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 = UPTR->un_sbufp; rbp = UPTR->un_rbufp; s = splr(srpri); 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); /* * check to see if the command is mode-2 read. If it is, * the driver has to switch the drive to mode 2, fire * the command and switch the drive back to mode 1. * The bp->b_flags should be set to busy all the time * so that other I/O request will not be serviced. */ if (addr_flag & SR_MODE2) { s = splr(srpri); while (rbp->b_flags & B_BUSY) { rbp->b_flags |= B_WANTED; (void) sleep((caddr_t) rbp, PRIBIO); } bzero((caddr_t) rbp, sizeof (struct buf)); rbp->b_flags |= B_BUSY; (void) splx(s); New_state(un, SR_STATE_MODE2); err = sr_mode_2(devp); if (err) { DPRINTF("srioctl_cmd: error in switching to mode-2\n"); New_state(un, SR_STATE_OPEN); goto done; } } /* * Set options. */ UPTR->un_soptions = 0; if ((scmd->uscsi_flags & DK_SILENT) && !(DEBUGGING_ALL)) { UPTR->un_soptions |= DK_SILENT; } if (scmd->uscsi_flags & DK_ISOLATE) UPTR->un_soptions |= DK_ISOLATE; if (scmd->uscsi_flags & DK_DIAGNOSE) UPTR->un_soptions |= DK_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; if ((scmd->uscsi_buflen) && !(addr_flag & SR_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; } } /* * If no errors, make and run the command. */ if (err == 0) { make_sr_cmd(devp, bp, SLEEP_FUNC); srstrategy(bp); s = splr(srpri); while ((bp->b_flags & B_DONE) == 0) { (void) sleep((caddr_t) bp, PRIBIO); } (void) splx(s); /* * get the status block */ scmd->uscsi_status = (int)SCBP_C(BP_PKT(bp)); DPRINTF("%s%d: status is %d\n", DNAME, DUNIT, scmd->uscsi_status); /* * Release the resources. * */ err = geterror(bp); 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)); } /* * see if the request was for mode-2 read. * If it was, the driver has to turn the read-mode back * to mode-1. */ if (addr_flag & SR_MODE2) { err1 = sr_mode_1(devp); New_state(un, SR_STATE_OPEN); if (err1) { DPRINTF("srioctl_cmd: error in switching to mode-1\n"); goto done; } } done: s = splr(srpri); if (bp->b_flags & B_WANTED) { wakeup((caddr_t)bp); } UPTR->un_soptions = 0; if (addr_flag & SR_MODE2) { if (rbp->b_flags & B_WANTED) { wakeup((caddr_t)rbp); } rbp->b_flags &= ~(B_BUSY|B_WANTED); } bp->b_flags &= ~(B_BUSY|B_WANTED); (void) splx(s); DPRINTF_IOCTL("returning %d from ioctl\n", err); return (err);}static voidsr_offline(devp)register struct scsi_device *devp;{ register struct scsi_disk *un = UPTR; printf("%s%d: offline or disc ejected\n", DNAME, DUNIT);#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_rbufp, (unsigned) (sizeof (struct buf))); (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, sizeof (struct scsi_inquiry)); devp->sd_inq = 0; devp->sd_sense = 0; devp->sd_present = 0;}static voidsr_not_ready(devp)register struct scsi_device *devp;{ register u_char *sb; sb = (u_char *)devp->sd_sense; switch (sb[12]) { case 0x04: printf("%s%d: logical unit not ready\n", DNAME, DUNIT); break; case 0x05: printf("%s%d: unit does not respond to selection\n", DNAME, DUNIT); break; case 0x3a: DPRINTF("%s%d: Caddy not inserted in drive\n", DNAME, DUNIT); sr_ejected(devp); break; default: printf("%s%d: Unit not Ready. Additional sense code %d\n", DNAME, DUNIT, sb[12]); break; }}static voidsr_ejected(devp)register struct scsi_device *devp;{ register struct scsi_disk *un = UPTR;#ifdef OPENPROMS (void) remdk((int) un->un_dkn);#endif OPENPROMS un->un_capacity = -1; un->un_lbasize = -1;}#ifdef OLDCODE/* * This routine checks and see if a new disc has been inserted. * It performs all the necessary actions. * It assumes the driver is in the SR_STATE_EJECTED driver state. */static intsr_read_new_disc(dev)dev_t dev;{ register struct scsi_device *devp; register struct scsi_disk *un; u_char state; devp = srunits[SRUNIT(dev)]; un = UPTR; New_state(un, SR_STATE_OPENING); if (sr_unit_ready(dev) == 0) { sr_not_ready(devp); return (0); } state = un->un_last_state; New_state(un, SR_STATE_OPENING); if (sr_read_capacity(dev) != 0) { un->un_state = un->un_last_state; un->un_last_state = state; return (0); } un->un_state = un->un_last_state; un->un_last_state = state; /* now lock the drive door */ state = un->un_last_state; New_state(un, SR_STATE_OPENING); if (sr_medium_removal(dev, SR_REMOVAL_PREVENT) != 0) { un->un_state = un->un_last_state; un->un_last_state = state; return (0); } un->un_state = un->un_last_state; un->un_last_state = state; New_state(un, SR_STATE_OPEN); printf("%s%d: disc inserted in drive\n", DNAME, DUNIT);#ifdef OPENPROMS sr_set_dkn(devp);#endif OPENPROMS return (1);}#endif OLDCODE/* * This routine called to see whether unit is (still) there. Must not * be called when un->un_sbufp is in use, and must not be called with * an unattached disk. Soft state of disk is restored to what it was * upon entry- up to caller to set the correct state. */static intsr_unit_ready(dev)dev_t dev;{ struct scsi_device *devp = srunits[SRUNIT(dev)]; struct scsi_disk *un = UPTR; auto struct uscsi_cmd cblk, *com = &cblk; u_char state = un->un_last_state; char cdb[6]; New_state(un, SR_STATE_OPENING); com->uscsi_bufaddr = 0; com->uscsi_buflen = 0; cdb[0] = SCMD_TEST_UNIT_READY; cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; cdb[4] = 0; cdb[5] = 0; com->uscsi_flags = DK_DIAGNOSE|DK_SILENT; com->uscsi_cdb = cdb; com->uscsi_cdblen = 6; /* * try it twice... */ if (srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL) && srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL)) { un->un_state = un->un_last_state; un->un_last_state = state; return (0); } un->un_state = un->un_last_state; un->un_last_state = state; return (1);}/* * makecom_all * note: for now, only bit 7 and bit 6 of the control byte in the cdb is * assigned. Those are the two vendor-unique control bits. */static voidmakecom_all(pkt, devp, flag, group, cdb)struct scsi_pkt *pkt;struct scsi_device *devp;int flag;int group;char *cdb;{ register union scsi_cdb *scsi_cdb; pkt->pkt_address = (devp)->sd_address; pkt->pkt_flags = flag; scsi_cdb = (union scsi_cdb *)pkt->pkt_cdbp; scsi_cdb->scc_cmd = cdb_cmd(cdb); scsi_cdb->scc_lun = pkt->pkt_address.a_lun; switch (group) { case 0: scsi_cdb->g0_addr2 = cdb_tag(cdb); scsi_cdb->g0_addr1 = (u_char)cdb[2]; scsi_cdb->g0_addr0 = (u_char)cdb[3]; scsi_cdb->g0_count0 = (u_char)cdb[4]; scsi_cdb->g0_vu_1 = cdb[5] & 0x80; scsi_cdb->g0_vu_0 = cdb[5] & 0x40; break; case 1: case 2: case 6: /* *edu: only for now. eventually, we will not *support group 6. */ scsi_cdb->g1_reladdr = cdb_tag(cdb); scsi_cdb->g1_addr3 = (u_char)cdb[2]; scsi_cdb->g1_addr2 = (u_char)cdb[3]; scsi_cdb->g1_addr1 = (u_char)cdb[4]; scsi_cdb->g1_addr0 = (u_char)cdb[5]; scsi_cdb->g1_rsvd0 = (u_char)cdb[6]; scsi_cdb->g1_count1 = (u_char)cdb[7]; scsi_cdb->g1_count0 = (u_char)cdb[8]; scsi_cdb->g1_vu_1 = cdb[9] & 0x80; scsi_cdb->g1_vu_0 = cdb[9] & 0x40; break; default: DPRINTF("makecom_all: does not support group %d\n", group); }}/* * This routine locks the cdrom door and prevent medium removal. */static intsr_medium_removal(dev, flag)dev_t dev;int flag;{ auto struct uscsi_cmd cblk, *com = &cblk; char cdb[6]; com->uscsi_bufaddr = 0; com->uscsi_buflen = 0; cdb[0] = SCMD_DOORLOCK; cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; cdb[4] = flag; cdb[5] = 0; com->uscsi_flags = DK_DIAGNOSE|DK_SILENT; com->uscsi_cdb = cdb; com->uscsi_cdblen = 6; return (srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL));}/* * This routine does a pause or resume to the cdrom player. Only affect * audio play operation. */static intsr_pause_resume(dev, data)dev_t dev;caddr_t data;{ int flag; struct uscsi_cmd cblk, *com=&cblk; char cdb[10]; flag = (int)data; bzero((caddr_t)cdb, 10); cdb[0] = SCMD_PAUSE_RESUME; cdb[8] = (flag == 0) ? 1 : 0; com->uscsi_cdb = cdb; com->uscsi_cdblen = 10; com->uscsi_bufaddr = 0; com->uscsi_buflen = 0; com->uscsi_flags = DK_DIAGNOSE|DK_SILENT; return (srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL));}/* * This routine plays audio by msf */static intsr_play_msf(dev, data)dev_t dev;caddr_t data;{ struct uscsi_cmd cblk, *com=&cblk; char cdb[10]; register struct cdrom_msf *msf; msf = (struct cdrom_msf *)data; bzero((caddr_t)cdb, 10); cdb[0] = SCMD_PLAYAUDIO_MSF; cdb[3] = msf->cdmsf_min0; cdb[4] = msf->cdmsf_sec0; cdb[5] = msf->cdmsf_frame0; cdb[6] = msf->cdmsf_min1; cdb[7] = msf->cdmsf_sec1; cdb[8] = msf->cdmsf_frame1; com->uscsi_cdb = cdb; com->uscsi_cdblen = 10; com->uscsi_bufaddr = 0; com->uscsi_buflen = 0; com->uscsi_flags = DK_DIAGNOSE|DK_SILENT; return (srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL));}/* * This routine plays audio by track/index */static intsr_play_trkind(dev, data)dev_t dev;caddr_t data;{ struct uscsi_cmd cblk, *com=&cblk; char cdb[10]; register struct cdrom_ti *ti; ti = (struct cdrom_ti *)data; bzero((caddr_t)cdb, 10); cdb[0] = SCMD_PLAYAUDIO_TI; cdb[4] = ti->cdti_trk0; cdb[5] = ti->cdti_ind0; cdb[7] = ti->cdti_trk1; cdb[8] = ti->cdti_ind1; com->uscsi_cdb = cdb; com->uscsi_cdblen = 10; com->uscsi_bufaddr = 0; com->uscsi_buflen = 0; com->uscsi_flags = DK_DIAGNOSE|DK_SILENT; return (srioctl_cmd(dev, (caddr_t)com, SR_USCSI_CDB_KERNEL));}/* * This routine starts the drive, stops the drive or ejects the disc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -