scsi_pt.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 748 行 · 第 1/2 页
C
748 行
/* * Implementation of SCSI Processor Target Peripheral driver for CAM. * * Copyright (c) 1998 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: scsi_pt.c,v 1.4.2.2 1999/05/09 01:27:42 ken Exp $ */#include <sys/param.h>#include <sys/queue.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/types.h>#include <sys/buf.h>#include <sys/devicestat.h>#include <sys/malloc.h>#include <sys/conf.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_extend.h>#include <cam/cam_periph.h>#include <cam/cam_xpt_periph.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_pt.h>typedef enum { PT_STATE_PROBE, PT_STATE_NORMAL} pt_state;typedef enum { PT_FLAG_NONE = 0x00, PT_FLAG_OPEN = 0x01, PT_FLAG_DEVICE_INVALID = 0x02, PT_FLAG_RETRY_UA = 0x04} pt_flags;typedef enum { PT_CCB_BUFFER_IO = 0x01, PT_CCB_WAITING = 0x02, PT_CCB_RETRY_UA = 0x04, PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA} pt_ccb_state;/* Offsets into our private area for storing information */#define ccb_state ppriv_field0#define ccb_bp ppriv_ptr1struct pt_softc { struct buf_queue_head buf_queue; struct devstat device_stats; LIST_HEAD(, ccb_hdr) pending_ccbs; pt_state state; pt_flags flags; union ccb saved_ccb;};static d_open_t ptopen;static d_read_t ptread;static d_write_t ptwrite;static d_close_t ptclose;static d_strategy_t ptstrategy;static periph_init_t ptinit;static void ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg);static periph_ctor_t ptctor;static periph_oninv_t ptoninvalidate;static periph_dtor_t ptdtor;static periph_start_t ptstart;static void ptdone(struct cam_periph *periph, union ccb *done_ccb);static int pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags);void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int tag_action, int readop, u_int byte2, u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, u_int32_t timeout);static struct periph_driver ptdriver ={ ptinit, "pt", TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0};DATA_SET(periphdriver_set, ptdriver);#define PT_CDEV_MAJOR 61static struct cdevsw pt_cdevsw = { /*d_open*/ ptopen, /*d_close*/ ptclose, /*d_read*/ ptread, /*d_write*/ ptwrite, /*d_ioctl*/ noioctl, /*d_stop*/ nostop, /*d_reset*/ noreset, /*d_devtotty*/ nodevtotty, /*d_poll*/ seltrue, /*d_mmap*/ nommap, /*d_strategy*/ ptstrategy, /*d_name*/ "pt", /*d_spare*/ NULL, /*d_maj*/ -1, /*d_dump*/ nodump, /*d_psize*/ nopsize, /*d_flags*/ 0, /*d_maxio*/ 0, /*b_maj*/ -1};static struct extend_array *ptperiphs;static intptopen(dev_t dev, int flags, int fmt, struct proc *p){ struct cam_periph *periph; struct pt_softc *softc; int unit; int error; int s; unit = minor(dev); periph = cam_extend_get(ptperiphs, unit); if (periph == NULL) return (ENXIO); softc = (struct pt_softc *)periph->softc; s = splsoftcam(); if (softc->flags & PT_FLAG_DEVICE_INVALID) { splx(s); return(ENXIO); } CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptopen: dev=0x%x (unit %d)\n", dev, unit)); if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { splx(s); return (error); /* error code from tsleep */ } splx(s); if ((softc->flags & PT_FLAG_OPEN) == 0) { if (cam_periph_acquire(periph) != CAM_REQ_CMP) error = ENXIO; else softc->flags |= PT_FLAG_OPEN; } else error = EBUSY; cam_periph_unlock(periph); return (error);}static intptclose(dev_t dev, int flag, int fmt, struct proc *p){ struct cam_periph *periph; struct pt_softc *softc; int unit; int error; unit = minor(dev); periph = cam_extend_get(ptperiphs, unit); if (periph == NULL) return (ENXIO); softc = (struct pt_softc *)periph->softc; if ((error = cam_periph_lock(periph, PRIBIO)) != 0) return (error); /* error code from tsleep */ softc->flags &= ~PT_FLAG_OPEN; cam_periph_unlock(periph); cam_periph_release(periph); return (0);}static intptread(dev_t dev, struct uio *uio, int ioflag){ return(physio(ptstrategy, NULL, dev, 1, minphys, uio));}static intptwrite(dev_t dev, struct uio *uio, int ioflag){ return(physio(ptstrategy, 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 voidptstrategy(struct buf *bp){ struct cam_periph *periph; struct pt_softc *softc; u_int unit; int s; unit = minor(bp->b_dev); periph = cam_extend_get(ptperiphs, unit); if (periph == NULL) { bp->b_error = ENXIO; goto bad; } softc = (struct pt_softc *)periph->softc; /* * 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(); /* * If the device has been made invalid, error out */ if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { splx(s); bp->b_error = ENXIO; goto bad; } /* * Place it in the queue of disk activities for this disk */ 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);}static voidptinit(void){ cam_status status; struct cam_path *path; /* * Create our extend array for storing the devices we attach to. */ ptperiphs = cam_extend_new(); if (ptperiphs == NULL) { printf("pt: Failed to alloc extend array!\n"); return; } /* * Install a global async callback. This callback will * receive async callbacks like "new device found". */ status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); if (status == CAM_REQ_CMP) { struct ccb_setasync csa; xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_FOUND_DEVICE; csa.callback = ptasync; csa.callback_arg = NULL; xpt_action((union ccb *)&csa); status = csa.ccb_h.status; xpt_free_path(path); } if (status != CAM_REQ_CMP) { printf("pt: Failed to attach master async callback " "due to status 0x%x!\n", status); } else { /* If we were successfull, register our devsw */ dev_t dev; dev = makedev(PT_CDEV_MAJOR, 0); cdevsw_add(&dev,&pt_cdevsw, NULL); }}static cam_statusptctor(struct cam_periph *periph, void *arg){ struct pt_softc *softc; struct ccb_setasync csa; struct ccb_getdev *cgd; cgd = (struct ccb_getdev *)arg; if (periph == NULL) { printf("ptregister: periph was NULL!!\n"); return(CAM_REQ_CMP_ERR); } if (cgd == NULL) { printf("ptregister: no getdev CCB, can't register device\n"); return(CAM_REQ_CMP_ERR); } softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); if (softc == NULL) { printf("daregister: Unable to probe new device. " "Unable to allocate softc\n"); return(CAM_REQ_CMP_ERR); } bzero(softc, sizeof(*softc)); LIST_INIT(&softc->pending_ccbs); softc->state = PT_STATE_NORMAL; bufq_init(&softc->buf_queue); periph->softc = softc; cam_extend_set(ptperiphs, periph->unit_number, periph); /* * The DA driver supports a blocksize, but * we don't know the blocksize until we do * a read capacity. So, set a flag to * indicate that the blocksize is * unavailable right now. We'll clear the * flag as soon as we've done a read capacity. */ devstat_add_entry(&softc->device_stats, "pt", periph->unit_number, 0, DEVSTAT_NO_BLOCKSIZE,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?