📄 sr.c
字号:
cdb[2] = 0x81; cdb[4] = 20; pkt1 = get_pktiopb(ROUTE, (caddr_t *)&buffer1, 6, 1, 20, B_READ, NULL_FUNC); if (!pkt1) { return (ENOMEM); } makecom_all(pkt1, devp, FLAG_NOINTR, 0, cdb); if (scsi_poll(pkt1) || SCBP_C(pkt1) != STATUS_GOOD || (pkt1->pkt_state & STATE_XFERRED_DATA) == 0 || (pkt1->pkt_resid != 0)) { DPRINTF("%s%d: MODE SENSE command failed.\n", DNAME, DUNIT); free_pktiopb(pkt1, (caddr_t)buffer1, 20); return (EIO); } DPRINTF("%s%d: Parameter from Mode Sense:\n", DNAME, DUNIT); if (DEBUGGING) { int i; for (i=0; i!=20; i++) { printf("0x%x ", buffer1[i]); } } /* * then, do a mode select to set to mode-1 read */ bzero((caddr_t)cdb, 6); cdb[0] = SCMD_MODE_SELECT; cdb[4] = 20; pkt2 = get_pktiopb(ROUTE, (caddr_t *)&buffer2, 6, 1, 20, B_WRITE, NULL_FUNC); if (!pkt2) { return (ENOMEM); } /* * fill in the parameter list for mode select command * values obtained from default value. */ bzero(buffer2, 20); buffer2[3] = 0x08;#ifdef FIVETWELVE /* * block length of 512 bytes - default mode 1 size */ buffer2[10] = 0x02;#else /* * set block length to 2048 bytes */ buffer2[10] = 0x08;#endif FIVETWELVE buffer2[11] = 0x00; buffer2[12] = 0x01; buffer2[13] = 0x06; buffer2[14] = buffer1[14]; buffer2[15] = buffer1[15]; /* * fire the command */ makecom_all(pkt2, devp, FLAG_NOINTR, 0, cdb); if (scsi_poll(pkt2) || SCBP_C(pkt2) != STATUS_GOOD || (pkt2->pkt_state & STATE_XFERRED_DATA) == 0 || (pkt2->pkt_resid != 0)) { DPRINTF("%s%d: MODE SELECT command failed.\n", DNAME, DUNIT); free_pktiopb(pkt2, (caddr_t)buffer2, 20); return (EIO); } free_pktiopb(pkt1, (caddr_t)buffer1, 20); free_pktiopb(pkt2, (caddr_t)buffer2, 20); return (0);}#ifndef FIVETWELVE/* * This routine sets the drive to read 2048 bytes per sector */static intsr_two_k(devp)struct scsi_device *devp;{ struct scsi_pkt *pkt1; struct scsi_pkt *pkt2; caddr_t buffer1; caddr_t buffer2; char cdb[6]; DPRINTF("%s%d: switching to reading 2048 bytes per sector.\n", DNAME, DUNIT); /* * first, do a mode sense of page 1 code */ bzero((caddr_t)cdb, 6); cdb[0] = SCMD_MODE_SENSE; /* get default page 1 values */ cdb[2] = 0x81; cdb[4] = 20; pkt1 = get_pktiopb(ROUTE, (caddr_t *)&buffer1, 6, 1, 20, B_READ, NULL_FUNC); if (!pkt1) { return (ENOMEM); } makecom_all(pkt1, devp, FLAG_NOINTR, 0, cdb); if (scsi_poll(pkt1) || SCBP_C(pkt1) != STATUS_GOOD || (pkt1->pkt_state & STATE_XFERRED_DATA) == 0 || (pkt1->pkt_resid != 0)) { DPRINTF("%s%d: MODE SENSE command failed.\n", DNAME, DUNIT); free_pktiopb(pkt1, (caddr_t)buffer1, 20); return (EIO); } DPRINTF("%s%d: Parameter from Mode Sense:\n", DNAME, DUNIT); if (DEBUGGING) { int i; for (i=0; i!=20; i++) { printf("0x%x ", buffer1[i]); } } /* * then, do a mode select to set to reading 2048 bytes per sector */ bzero(cdb, 6); cdb[0] = SCMD_MODE_SELECT; cdb[4] = 20; pkt2 = get_pktiopb(ROUTE, (caddr_t *)&buffer2, 6, 1, 20, B_WRITE, NULL_FUNC); if (!pkt2) { return (ENOMEM); } /* * fill in the parameter list for mode select command * values obtained from default value. */ bzero(buffer2, 20); buffer2[3] = 0x08; /* * block length of 2048 bytes (hex 800) */ buffer2[10] = 0x08; buffer2[11] = 0x00; buffer2[12] = 0x01; buffer2[13] = 0x06; buffer2[14] = buffer1[14]; buffer2[15] = buffer1[15]; /* * fire the command */ makecom_all(pkt2, devp, FLAG_NOINTR, 0, cdb); if (scsi_poll(pkt2) || SCBP_C(pkt2) != STATUS_GOOD || (pkt2->pkt_state & STATE_XFERRED_DATA) == 0 || (pkt2->pkt_resid != 0)) { DPRINTF("%s%d: MODE SELECT command failed.\n", DNAME, DUNIT); free_pktiopb(pkt2, (caddr_t)buffer2, 20); return (EIO); } free_pktiopb(pkt1, (caddr_t)buffer1, 20); free_pktiopb(pkt2, (caddr_t)buffer2, 20); return (0);}#endif/* * This routine locks the drive door */static intsr_lock_door(devp)struct scsi_device *devp;{ struct scsi_pkt *pkt; char cdb[6]; DPRINTF("%s%d: locking the drive door\n", DNAME, DUNIT); bzero(cdb, 6); cdb[0] = SCMD_DOORLOCK; cdb[4] = 0x01; pkt = scsi_pktalloc(ROUTE, CDB_GROUP0, 1, NULL_FUNC); if (!pkt) { return (ENOMEM); } makecom_all(pkt, devp, FLAG_NOINTR, 0, cdb); if (scsi_poll(pkt) || SCBP_C(pkt) != STATUS_GOOD) { DPRINTF("%s%d: Prevent/Allow Medium Removal command failed.\n", DNAME, DUNIT); scsi_resfree(pkt); return (EIO); } scsi_resfree(pkt); return (0);}/* * This routine read the drive's capacity and logical block size */static intsr_read_capacity(devp)struct scsi_device *devp;{ struct scsi_pkt *pkt; caddr_t buffer; register struct scsi_disk *un; DPRINTF("%s%d: reading the drive's capacity\n", DNAME, DUNIT);#ifdef OPENPROMS sr_set_dkn(devp);#endif OPENPROMS un = UPTR; pkt = get_pktiopb(ROUTE, &buffer, CDB_GROUP1, 1, sizeof (struct scsi_capacity), B_READ, NULL_FUNC); if (!pkt) { return (ENOMEM); } makecom_g1(pkt, devp, 0, SCMD_READ_CAPACITY, 0, 0); if ((scsi_poll(pkt) == 0) && (SCBP_C(pkt) == STATUS_GOOD) && (pkt->pkt_state & STATE_XFERRED_DATA) && (pkt->pkt_resid == 0)) { un->un_capacity = ((struct scsi_capacity *)buffer)->capacity+1; un->un_lbasize = ((struct scsi_capacity *)buffer)->lbasize; free_pktiopb(pkt, buffer, sizeof (struct scsi_capacity)); return (0); } else { free_pktiopb(pkt, buffer, sizeof (struct scsi_capacity)); return (EIO); }}/* * * Unit start and Completion * */static voidsrstart(devp)register struct scsi_device *devp;{ register struct buf *bp; register struct scsi_disk *un = UPTR; register struct diskhd *dp = &un->un_utab; DPRINTF("srstart\n"); if (dp->b_forw) { printf("srstart: busy already\n"); return; } else if ((bp = dp->b_actf) == NULL) { DPRINTF("%s%d: srstart idle\n", DNAME, DUNIT); return; } if (!BP_PKT(bp)) { make_sr_cmd(devp, bp, srrunout); if (!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, SR_STATE_RWAIT); return; } else { New_state(un, SR_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 ((scsi_options & SCSI_OPTIONS_LINK) && (un->un_dp->options & SR_DOLINK) && dp->b_actf && bp != un->un_sbufp && CDBP(BP_PKT(bp))->g0_link == 0) { if (BP_PKT(dp->b_actf)) { CDBP(BP_PKT(bp))->g0_link = 1; } else { make_sr_cmd(devp, dp->b_actf, NULL_FUNC); if (BP_PKT(dp->b_actf)) { CDBP(BP_PKT(bp))->g0_link = 1; } } } if (pkt_transport(BP_PKT(bp)) == 0) { printf("%s%d: transport rejected\n", DNAME, DUNIT); bp->b_flags |= B_ERROR; srdone(devp); } else if (dp->b_actf && !BP_PKT(dp->b_actf)) { make_sr_cmd(devp, dp->b_actf, NULL_FUNC); }}static intsrrunout(){ register i, s = splr(srpri); register struct scsi_device *devp; register struct scsi_disk *un; for (i = 0; i < nsr; i++) { devp = srunits[i]; if (devp && devp->sd_present && (un=UPTR) && un->un_gvalid) { if (un->un_state == SR_STATE_RWAIT) { DPRINTF("%s%d: resource retry\n", DNAME, DUNIT); srstart(devp); if (un->un_state == SR_STATE_RWAIT) { (void) splx(s); return (0); } DPRINTF("%s%d: resource gotten\n", DNAME, DUNIT); } } } (void) splx(s); return (1);}static voidsrdone(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) { DPRINTF("%s%d: srdone calling srstart\n", DNAME, DUNIT); srstart(devp); } if (bp != un->un_sbufp) { scsi_resfree(BP_PKT(bp)); iodone(bp); DPRINTF("%s%d: regular done resid %d\n", DNAME, DUNIT, bp->b_resid); } else { DPRINTF("%s%d: special done resid %d\n", DNAME, DUNIT, bp->b_resid); bp->b_flags |= B_DONE; wakeup((caddr_t) bp); }}static voidmake_sr_cmd(devp, bp, func)register struct scsi_device *devp;register struct buf *bp;int (*func)();{ register struct scsi_pkt *pkt; register struct scsi_disk *un = UPTR; register daddr_t blkno = 0; int tval = DEFAULT_SR_TIMEOUT, count, com, flags; char *cdb; flags = (scsi_options & SCSI_OPTIONS_DR) ? 0: FLAG_NODISCON; if (bp != un->un_sbufp) { long blkovr; DPRINTF("make_sr_cmd: regular\n"); pkt = scsi_resalloc(ROUTE, CDB_GROUP0, 1, (opaque_t)bp, func); if ((BP_PKT(bp) = pkt) == (struct scsi_pkt *) 0) { return; } /* count is number of blocks */ count = bp->b_bcount >> SECDIV;#ifdef FIVETWELVE blkno = dkblock(bp);#else /* shift block number. since block size is 2048 */ blkno = dkblock(bp) >> 2;#endif FIVETWELVE DPRINTF("bp->b_bcount is %d\n", bp->b_bcount); DPRINTF("count is %d\n", count); DPRINTF("blkno is %d\n", blkno); /* * Make sure we don't run off the end of the CDROM */ if ((blkovr = blkno + count - un->un_capacity) > 0) { DPRINTF("%s%d: (%d, %d) overrun by %d blocks\n", DNAME, DUNIT, blkno, bp->b_bcount, blkovr); bp->b_resid = (blkovr << SECDIV); count -= blkovr; } else { bp->b_resid = 0; } if (bp->b_flags & B_READ) { DPRINTF("%s%d: read", DNAME, DUNIT); com = SCMD_READ; } else { DPRINTF("%s%d: write", DNAME, DUNIT); com = SCMD_WRITE; } DPRINTF(" blk %d amt 0x%x (%d) resid %d\n", blkno, count<<SECDIV, count<<SECDIV, bp->b_resid); makecom_g0(pkt, devp, flags, com, (int) blkno, count); pkt->pkt_pmon = un->un_dkn; } else { struct buf *abp = bp; int group; /* * Some commands are group 1 commands, some are group 0. * It is legitimate to allocate a cdb sufficient for any. * Therefore, we'll ask for a GROUP 1 cdb. */ /* * stored in bp->b_forw is a pointer to cdb */ cdb = (char *)bp->b_forw; com = (int)cdb_cmd(cdb); group = ((unsigned char)com) >> 5; blkno = bp->b_blkno; count = bp->b_bcount; DPRINTF("%s%d: blkno is %d, count is %d ", DNAME, DUNIT, blkno, count); switch (com) { case SCMD_READ: DPRINTF_IOCTL("special %s\n", (com==SCMD_READ)?"read": "write"); count = bp->b_bcount >> SECDIV; break; default: DPRINTF_IOCTL("scsi command 0x%x\n", com); if (bp->b_bcount == 0) { abp = (struct buf *)0; } break; } pkt = scsi_resalloc(ROUTE, CDB_GROUP1, 1, (opaque_t)abp, SLEEP_FUNC); makecom_all(pkt, devp, flags, group, cdb); pkt->pkt_pmon = -1; } if (un->un_dp->options & SR_NODISC) pkt->pkt_flags |= FLAG_NODISCON; pkt->pkt_comp = srintr; pkt->pkt_time = tval; pkt->pkt_private = (opaque_t) bp; BP_PKT(bp) = pkt;}/* * * Interrupt Service Routines * *//* * */staticsrrestart(arg)caddr_t arg;{ struct scsi_device *devp = (struct scsi_device *) arg; struct buf *bp; register s = splr(srpri); printf("srrestart\n"); if ((bp = UPTR->un_utab.b_forw) == 0) { printf("%s%d: busy restart aborted\n", DNAME, DUNIT); } else { struct scsi_pkt *pkt; if (UPTR->un_state == SR_STATE_SENSING) { pkt = UPTR->un_rqs; } else { pkt = BP_PKT(bp); } if (pkt_transport(pkt) == 0) { printf("%s%d: restart transport failed\n", DNAME, DUNIT); UPTR->un_state = UPTR->un_last_state; bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; srdone(devp); } } (void) splx(s);}/* * Command completion processing * */static voidsrintr(pkt)struct scsi_pkt *pkt;{ register struct scsi_device *devp; register struct scsi_disk *un; register struct buf *bp; register action; /* * Do some sanity checking */ if (!pkt) { printf("sdintr: null packet?\n"); return; } else if (pkt->pkt_flags & FLAG_NOINTR) { printf("srintr:internal error - got a non-interrupting cmd\n"); return; } else if ((bp = (struct buf *) pkt->pkt_private) == 0) { printf("sdintr: packet with no buffer pointer\n"); return; } if (!(devp = srunits[SRUNIT(bp->b_dev)]) || !(un = UPTR)) { printf("srintr: mangled data structures\n"); return; } else if (bp != un->un_utab.b_forw) { printf("srintr: completed packet's buffer not on queue\n"); return; } DPRINTF("srintr:\n"); if (pkt->pkt_reason != CMD_CMPLT) { action = sr_handle_incomplete(devp); /* * At this point we know that the command was successfully * completed. Now what? */ } else if (un->un_state == SR_STATE_SENSING) { /* * okay. W
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -