scsi_pass.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 861 行 · 第 1/2 页
C
861 行
return (error); } splx(s); if ((softc->flags & PASS_FLAG_OPEN) == 0) { if (cam_periph_acquire(periph) != CAM_REQ_CMP) return(ENXIO); softc->flags |= PASS_FLAG_OPEN; } cam_periph_unlock(periph); return (error);}static intpassclose(dev_t dev, int flag, int fmt, struct proc *p){ struct cam_periph *periph; struct pass_softc *softc; int unit, error; /* unit = dkunit(dev); */ /* XXX KDM fix this */ unit = minor(dev) & 0xff; periph = cam_extend_get(passperiphs, unit); if (periph == NULL) return (ENXIO); softc = (struct pass_softc *)periph->softc; if ((error = cam_periph_lock(periph, PRIBIO)) != 0) return (error); softc->flags &= ~PASS_FLAG_OPEN; cam_periph_unlock(periph); cam_periph_release(periph); return (0);}static intpassread(dev_t dev, struct uio *uio, int ioflag){ return(physio(passstrategy, NULL, dev, 1, minphys, uio));}static intpasswrite(dev_t dev, struct uio *uio, int ioflag){ return(physio(passstrategy, NULL, dev, 0, minphys, uio));}/* * Actually translate the requested transfer into one the physical driver * can understand. The transfer is described by a buf and will include * only one physical transfer. */static voidpassstrategy(struct buf *bp){ struct cam_periph *periph; struct pass_softc *softc; u_int unit; int s; /* * The read/write interface for the passthrough driver doesn't * really work right now. So, we just pass back EINVAL to tell the * user to go away. */ bp->b_error = EINVAL; goto bad; /* unit = dkunit(bp->b_dev); */ /* XXX KDM fix this */ unit = minor(bp->b_dev) & 0xff; periph = cam_extend_get(passperiphs, unit); if (periph == NULL) { bp->b_error = ENXIO; goto bad; } softc = (struct pass_softc *)periph->softc; /* * Odd number of bytes or negative offset */ /* valid request? */ if (bp->b_blkno < 0) { bp->b_error = EINVAL; goto bad; } /* * Mask interrupts so that the pack cannot be invalidated until * after we are in the queue. Otherwise, we might not properly * clean up one of the buffers. */ s = splbio(); bufq_insert_tail(&softc->buf_queue, bp); splx(s); /* * Schedule ourselves for performing the work. */ xpt_schedule(periph, /* XXX priority */1); return;bad: bp->b_flags |= B_ERROR; /* * Correctly set the buf to indicate a completed xfer */ bp->b_resid = bp->b_bcount; biodone(bp); return;}static voidpassstart(struct cam_periph *periph, union ccb *start_ccb){ struct pass_softc *softc; int s; softc = (struct pass_softc *)periph->softc; switch (softc->state) { case PASS_STATE_NORMAL: { struct buf *bp; s = splbio(); bp = bufq_first(&softc->buf_queue); if (periph->immediate_priority <= periph->pinfo.priority) { start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; splx(s); wakeup(&periph->ccb_list); } else if (bp == NULL) { splx(s); xpt_release_ccb(start_ccb); } else { bufq_remove(&softc->buf_queue, bp); devstat_start_transaction(&softc->device_stats); /* * XXX JGibbs - * Interpret the contents of the bp as a CCB * and pass it to a routine shared by our ioctl * code and passtart. * For now, just biodone it with EIO so we don't * hang. */ bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; biodone(bp); bp = bufq_first(&softc->buf_queue); splx(s); xpt_action(start_ccb); } if (bp != NULL) { /* Have more work to do, so ensure we stay scheduled */ xpt_schedule(periph, /* XXX priority */1); } break; } }}static voidpassdone(struct cam_periph *periph, union ccb *done_ccb){ struct pass_softc *softc; struct ccb_scsiio *csio; softc = (struct pass_softc *)periph->softc; csio = &done_ccb->csio; switch (csio->ccb_h.ccb_type) { case PASS_CCB_BUFFER_IO: { struct buf *bp; cam_status status; u_int8_t scsi_status; devstat_trans_flags ds_flags; status = done_ccb->ccb_h.status; scsi_status = done_ccb->csio.scsi_status; bp = (struct buf *)done_ccb->ccb_h.ccb_bp; /* XXX handle errors */ if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) && (scsi_status == SCSI_STATUS_OK))) { int error; if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { /* * A retry was scheuled, so * just return. */ return; } /* * XXX unfreeze the queue after we complete * the abort process */ bp->b_error = error; bp->b_flags |= B_ERROR; } if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) ds_flags = DEVSTAT_READ; else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) ds_flags = DEVSTAT_WRITE; else ds_flags = DEVSTAT_NO_DATA; devstat_end_transaction(&softc->device_stats, bp->b_bcount, done_ccb->csio.tag_action & 0xf, ds_flags); biodone(bp); break; } case PASS_CCB_WAITING: { /* Caller will release the CCB */ wakeup(&done_ccb->ccb_h.cbfcnp); return; } } xpt_release_ccb(done_ccb);}static intpassioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p){ struct cam_periph *periph; struct pass_softc *softc; u_int8_t unit; int error; /* unit = dkunit(dev); */ /* XXX KDM fix this */ unit = minor(dev) & 0xff; periph = cam_extend_get(passperiphs, unit); if (periph == NULL) return(ENXIO); softc = (struct pass_softc *)periph->softc; error = 0; switch (cmd) { case CAMIOCOMMAND: { union ccb *inccb; union ccb *ccb; int ccb_malloced; inccb = (union ccb *)addr; /* * Some CCB types, like scan bus and scan lun can only go * through the transport layer device. */ if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { xpt_print_path(periph->path); printf("CCB function code %#x is restricted to the " "XPT device\n", inccb->ccb_h.func_code); error = ENODEV; break; } /* * Non-immediate CCBs need a CCB from the per-device pool * of CCBs, which is scheduled by the transport layer. * Immediate CCBs and user-supplied CCBs should just be * malloced. */ if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { ccb = cam_periph_getccb(periph, inccb->ccb_h.pinfo.priority); ccb_malloced = 0; } else { ccb = xpt_alloc_ccb(); if (ccb != NULL) xpt_setup_ccb(&ccb->ccb_h, periph->path, inccb->ccb_h.pinfo.priority); ccb_malloced = 1; } if (ccb == NULL) { xpt_print_path(periph->path); printf("unable to allocate CCB\n"); error = ENOMEM; break; } error = passsendccb(periph, ccb, inccb); if (ccb_malloced) xpt_free_ccb(ccb); else xpt_release_ccb(ccb); break; } default: error = cam_periph_ioctl(periph, cmd, addr, passerror); break; } return(error);}/* * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" * should be the CCB that is copied in from the user. */static intpasssendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb){ struct pass_softc *softc; struct cam_periph_map_info mapinfo; int error, need_unmap; softc = (struct pass_softc *)periph->softc; need_unmap = 0; /* * There are some fields in the CCB header that need to be * preserved, the rest we get from the user. */ xpt_merge_ccb(ccb, inccb); /* * There's no way for the user to have a completion * function, so we put our own completion function in here. */ ccb->ccb_h.cbfcnp = passdone; /* * We only attempt to map the user memory into kernel space * if they haven't passed in a physical memory pointer, * and if there is actually an I/O operation to perform. * Right now cam_periph_mapmem() only supports SCSI and device * match CCBs. For the SCSI CCBs, we only pass the CCB in if * there's actually data to map. cam_periph_mapmem() will do the * right thing, even if there isn't data to map, but since CCBs * without data are a reasonably common occurance (e.g. test unit * ready), it will save a few cycles if we check for it here. */ if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) && (((ccb->ccb_h.func_code == XPT_SCSI_IO) && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { bzero(&mapinfo, sizeof(mapinfo)); error = cam_periph_mapmem(ccb, &mapinfo); /* * cam_periph_mapmem returned an error, we can't continue. * Return the error to the user. */ if (error) return(error); /* * We successfully mapped the memory in, so we need to * unmap it when the transaction is done. */ need_unmap = 1; } /* * If the user wants us to perform any error recovery, then honor * that request. Otherwise, it's up to the user to perform any * error recovery. */ error = cam_periph_runccb(ccb, (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? passerror : NULL, /* cam_flags */ 0, /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, &softc->device_stats); if (need_unmap != 0) cam_periph_unmapmem(ccb, &mapinfo); ccb->ccb_h.cbfcnp = NULL; ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; bcopy(ccb, inccb, sizeof(union ccb)); return(error);}static intpasserror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags){ struct cam_periph *periph; struct pass_softc *softc; periph = xpt_path_periph(ccb->ccb_h.path); softc = (struct pass_softc *)periph->softc; return(cam_periph_error(ccb, cam_flags, sense_flags, &softc->saved_ccb));}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?