1898b0535SWarner Losh /*- 276babe50SJustin T. Gibbs * Implementation of SCSI Processor Target Peripheral driver for CAM. 376babe50SJustin T. Gibbs * 476babe50SJustin T. Gibbs * Copyright (c) 1998 Justin T. Gibbs. 576babe50SJustin T. Gibbs * All rights reserved. 676babe50SJustin T. Gibbs * 776babe50SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 876babe50SJustin T. Gibbs * modification, are permitted provided that the following conditions 976babe50SJustin T. Gibbs * are met: 1076babe50SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 1176babe50SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 1276babe50SJustin T. Gibbs * without modification, immediately at the beginning of the file. 1376babe50SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 1476babe50SJustin T. Gibbs * derived from this software without specific prior written permission. 1576babe50SJustin T. Gibbs * 1676babe50SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1776babe50SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1876babe50SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1976babe50SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2076babe50SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2176babe50SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2276babe50SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2376babe50SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2476babe50SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2576babe50SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2676babe50SJustin T. Gibbs * SUCH DAMAGE. 2776babe50SJustin T. Gibbs */ 2876babe50SJustin T. Gibbs 29ee709e70SDavid E. O'Brien #include <sys/cdefs.h> 30ee709e70SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31ee709e70SDavid E. O'Brien 3276babe50SJustin T. Gibbs #include <sys/param.h> 3376babe50SJustin T. Gibbs #include <sys/queue.h> 3476babe50SJustin T. Gibbs #include <sys/systm.h> 3576babe50SJustin T. Gibbs #include <sys/kernel.h> 3676babe50SJustin T. Gibbs #include <sys/types.h> 379626b608SPoul-Henning Kamp #include <sys/bio.h> 3876babe50SJustin T. Gibbs #include <sys/devicestat.h> 3976babe50SJustin T. Gibbs #include <sys/malloc.h> 4076babe50SJustin T. Gibbs #include <sys/conf.h> 413ece1bd2SKenneth D. Merry #include <sys/ptio.h> 4276babe50SJustin T. Gibbs 4376babe50SJustin T. Gibbs #include <cam/cam.h> 4476babe50SJustin T. Gibbs #include <cam/cam_ccb.h> 4576babe50SJustin T. Gibbs #include <cam/cam_periph.h> 4676babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h> 4776babe50SJustin T. Gibbs #include <cam/cam_debug.h> 4876babe50SJustin T. Gibbs 4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h> 5176babe50SJustin T. Gibbs #include <cam/scsi/scsi_pt.h> 5276babe50SJustin T. Gibbs 533ece1bd2SKenneth D. Merry #include "opt_pt.h" 543ece1bd2SKenneth D. Merry 5576babe50SJustin T. Gibbs typedef enum { 5676babe50SJustin T. Gibbs PT_STATE_PROBE, 5776babe50SJustin T. Gibbs PT_STATE_NORMAL 5876babe50SJustin T. Gibbs } pt_state; 5976babe50SJustin T. Gibbs 6076babe50SJustin T. Gibbs typedef enum { 6176babe50SJustin T. Gibbs PT_FLAG_NONE = 0x00, 6276babe50SJustin T. Gibbs PT_FLAG_OPEN = 0x01, 6376babe50SJustin T. Gibbs PT_FLAG_DEVICE_INVALID = 0x02, 6476babe50SJustin T. Gibbs PT_FLAG_RETRY_UA = 0x04 6576babe50SJustin T. Gibbs } pt_flags; 6676babe50SJustin T. Gibbs 6776babe50SJustin T. Gibbs typedef enum { 6876babe50SJustin T. Gibbs PT_CCB_BUFFER_IO = 0x01, 6976babe50SJustin T. Gibbs PT_CCB_WAITING = 0x02, 7076babe50SJustin T. Gibbs PT_CCB_RETRY_UA = 0x04, 7176babe50SJustin T. Gibbs PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 7276babe50SJustin T. Gibbs } pt_ccb_state; 7376babe50SJustin T. Gibbs 7476babe50SJustin T. Gibbs /* Offsets into our private area for storing information */ 7576babe50SJustin T. Gibbs #define ccb_state ppriv_field0 7676babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 7776babe50SJustin T. Gibbs 7876babe50SJustin T. Gibbs struct pt_softc { 798177437dSPoul-Henning Kamp struct bio_queue_head bio_queue; 80a9d2245eSPoul-Henning Kamp struct devstat *device_stats; 81e3975643SJake Burkholder LIST_HEAD(, ccb_hdr) pending_ccbs; 8276babe50SJustin T. Gibbs pt_state state; 8376babe50SJustin T. Gibbs pt_flags flags; 8476babe50SJustin T. Gibbs union ccb saved_ccb; 853ece1bd2SKenneth D. Merry int io_timeout; 8689c9c53dSPoul-Henning Kamp struct cdev *dev; 8776babe50SJustin T. Gibbs }; 8876babe50SJustin T. Gibbs 8976babe50SJustin T. Gibbs static d_open_t ptopen; 9076babe50SJustin T. Gibbs static d_close_t ptclose; 9176babe50SJustin T. Gibbs static d_strategy_t ptstrategy; 9276babe50SJustin T. Gibbs static periph_init_t ptinit; 9376babe50SJustin T. Gibbs static void ptasync(void *callback_arg, u_int32_t code, 9476babe50SJustin T. Gibbs struct cam_path *path, void *arg); 9576babe50SJustin T. Gibbs static periph_ctor_t ptctor; 96ee9c90c7SKenneth D. Merry static periph_oninv_t ptoninvalidate; 9776babe50SJustin T. Gibbs static periph_dtor_t ptdtor; 9876babe50SJustin T. Gibbs static periph_start_t ptstart; 9976babe50SJustin T. Gibbs static void ptdone(struct cam_periph *periph, 10076babe50SJustin T. Gibbs union ccb *done_ccb); 1013ece1bd2SKenneth D. Merry static d_ioctl_t ptioctl; 10276babe50SJustin T. Gibbs static int pterror(union ccb *ccb, u_int32_t cam_flags, 10376babe50SJustin T. Gibbs u_int32_t sense_flags); 10476babe50SJustin T. Gibbs 10576babe50SJustin T. Gibbs void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 10676babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 10776babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2, 10876babe50SJustin T. Gibbs u_int32_t xfer_len, u_int8_t *data_ptr, 10976babe50SJustin T. Gibbs u_int8_t sense_len, u_int32_t timeout); 11076babe50SJustin T. Gibbs 11176babe50SJustin T. Gibbs static struct periph_driver ptdriver = 11276babe50SJustin T. Gibbs { 11376babe50SJustin T. Gibbs ptinit, "pt", 11476babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 11576babe50SJustin T. Gibbs }; 11676babe50SJustin T. Gibbs 1170b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pt, ptdriver); 11876babe50SJustin T. Gibbs 11976babe50SJustin T. Gibbs 1204e2f199eSPoul-Henning Kamp static struct cdevsw pt_cdevsw = { 121dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1222b83592fSScott Long .d_flags = 0, 1237ac40f5fSPoul-Henning Kamp .d_open = ptopen, 1247ac40f5fSPoul-Henning Kamp .d_close = ptclose, 1257ac40f5fSPoul-Henning Kamp .d_read = physread, 1267ac40f5fSPoul-Henning Kamp .d_write = physwrite, 1277ac40f5fSPoul-Henning Kamp .d_ioctl = ptioctl, 1287ac40f5fSPoul-Henning Kamp .d_strategy = ptstrategy, 1297ac40f5fSPoul-Henning Kamp .d_name = "pt", 13076babe50SJustin T. Gibbs }; 13176babe50SJustin T. Gibbs 1323ece1bd2SKenneth D. Merry #ifndef SCSI_PT_DEFAULT_TIMEOUT 1333ece1bd2SKenneth D. Merry #define SCSI_PT_DEFAULT_TIMEOUT 60 1343ece1bd2SKenneth D. Merry #endif 1353ece1bd2SKenneth D. Merry 13676babe50SJustin T. Gibbs static int 13789c9c53dSPoul-Henning Kamp ptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 13876babe50SJustin T. Gibbs { 13976babe50SJustin T. Gibbs struct cam_periph *periph; 14076babe50SJustin T. Gibbs struct pt_softc *softc; 1412b83592fSScott Long int error = 0; 14276babe50SJustin T. Gibbs 143e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 1442b83592fSScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) 14576babe50SJustin T. Gibbs return (ENXIO); 14676babe50SJustin T. Gibbs 14776babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 14876babe50SJustin T. Gibbs 1492b83592fSScott Long cam_periph_lock(periph); 150ee9c90c7SKenneth D. Merry if (softc->flags & PT_FLAG_DEVICE_INVALID) { 151c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 1522b83592fSScott Long cam_periph_unlock(periph); 153ee9c90c7SKenneth D. Merry return(ENXIO); 154ee9c90c7SKenneth D. Merry } 155ee9c90c7SKenneth D. Merry 1562b83592fSScott Long if ((softc->flags & PT_FLAG_OPEN) == 0) 1572b83592fSScott Long softc->flags |= PT_FLAG_OPEN; 1582b83592fSScott Long else { 1592b83592fSScott Long error = EBUSY; 1602b83592fSScott Long cam_periph_release(periph); 16122b9c86cSKenneth D. Merry } 16222b9c86cSKenneth D. Merry 1632b83592fSScott Long CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 1642b83592fSScott Long ("ptopen: dev=%s\n", devtoname(dev))); 16576babe50SJustin T. Gibbs 16676babe50SJustin T. Gibbs cam_periph_unlock(periph); 16776babe50SJustin T. Gibbs return (error); 16876babe50SJustin T. Gibbs } 16976babe50SJustin T. Gibbs 17076babe50SJustin T. Gibbs static int 17189c9c53dSPoul-Henning Kamp ptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 17276babe50SJustin T. Gibbs { 17376babe50SJustin T. Gibbs struct cam_periph *periph; 17476babe50SJustin T. Gibbs struct pt_softc *softc; 17576babe50SJustin T. Gibbs 176e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 17776babe50SJustin T. Gibbs if (periph == NULL) 17876babe50SJustin T. Gibbs return (ENXIO); 17976babe50SJustin T. Gibbs 18076babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 18176babe50SJustin T. Gibbs 1822b83592fSScott Long cam_periph_lock(periph); 18376babe50SJustin T. Gibbs 18476babe50SJustin T. Gibbs softc->flags &= ~PT_FLAG_OPEN; 185c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 18676babe50SJustin T. Gibbs cam_periph_unlock(periph); 18776babe50SJustin T. Gibbs return (0); 18876babe50SJustin T. Gibbs } 18976babe50SJustin T. Gibbs 19076babe50SJustin T. Gibbs /* 19176babe50SJustin T. Gibbs * Actually translate the requested transfer into one the physical driver 19276babe50SJustin T. Gibbs * can understand. The transfer is described by a buf and will include 19376babe50SJustin T. Gibbs * only one physical transfer. 19476babe50SJustin T. Gibbs */ 19576babe50SJustin T. Gibbs static void 1968177437dSPoul-Henning Kamp ptstrategy(struct bio *bp) 19776babe50SJustin T. Gibbs { 19876babe50SJustin T. Gibbs struct cam_periph *periph; 19976babe50SJustin T. Gibbs struct pt_softc *softc; 20076babe50SJustin T. Gibbs 201e2a5fdf9SNate Lawson periph = (struct cam_periph *)bp->bio_dev->si_drv1; 202b63170f8SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 20376babe50SJustin T. Gibbs if (periph == NULL) { 204b63170f8SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 205b63170f8SPoul-Henning Kamp return; 20676babe50SJustin T. Gibbs } 2072b83592fSScott Long cam_periph_lock(periph); 20876babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 20976babe50SJustin T. Gibbs 21076babe50SJustin T. Gibbs /* 21176babe50SJustin T. Gibbs * If the device has been made invalid, error out 21276babe50SJustin T. Gibbs */ 21376babe50SJustin T. Gibbs if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 2142b83592fSScott Long cam_periph_unlock(periph); 215b63170f8SPoul-Henning Kamp biofinish(bp, NULL, ENXIO); 216b63170f8SPoul-Henning Kamp return; 21776babe50SJustin T. Gibbs } 21876babe50SJustin T. Gibbs 21976babe50SJustin T. Gibbs /* 22076babe50SJustin T. Gibbs * Place it in the queue of disk activities for this disk 22176babe50SJustin T. Gibbs */ 2228177437dSPoul-Henning Kamp bioq_insert_tail(&softc->bio_queue, bp); 22376babe50SJustin T. Gibbs 22476babe50SJustin T. Gibbs /* 22576babe50SJustin T. Gibbs * Schedule ourselves for performing the work. 22676babe50SJustin T. Gibbs */ 227bbfa4aa1SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 2282b83592fSScott Long cam_periph_unlock(periph); 22976babe50SJustin T. Gibbs 23076babe50SJustin T. Gibbs return; 23176babe50SJustin T. Gibbs } 23276babe50SJustin T. Gibbs 23376babe50SJustin T. Gibbs static void 23476babe50SJustin T. Gibbs ptinit(void) 23576babe50SJustin T. Gibbs { 23676babe50SJustin T. Gibbs cam_status status; 23776babe50SJustin T. Gibbs 23876babe50SJustin T. Gibbs /* 23976babe50SJustin T. Gibbs * Install a global async callback. This callback will 24076babe50SJustin T. Gibbs * receive async callbacks like "new device found". 24176babe50SJustin T. Gibbs */ 24285d92640SScott Long status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL); 24376babe50SJustin T. Gibbs 24476babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 24576babe50SJustin T. Gibbs printf("pt: Failed to attach master async callback " 24676babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 24776babe50SJustin T. Gibbs } 24876babe50SJustin T. Gibbs } 24976babe50SJustin T. Gibbs 25076babe50SJustin T. Gibbs static cam_status 25176babe50SJustin T. Gibbs ptctor(struct cam_periph *periph, void *arg) 25276babe50SJustin T. Gibbs { 25376babe50SJustin T. Gibbs struct pt_softc *softc; 25476babe50SJustin T. Gibbs struct ccb_getdev *cgd; 255b8b6b5d3SAlexander Motin struct ccb_pathinq cpi; 25676babe50SJustin T. Gibbs 25776babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 25876babe50SJustin T. Gibbs if (periph == NULL) { 25976babe50SJustin T. Gibbs printf("ptregister: periph was NULL!!\n"); 26076babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 26176babe50SJustin T. Gibbs } 26276babe50SJustin T. Gibbs 26376babe50SJustin T. Gibbs if (cgd == NULL) { 26476babe50SJustin T. Gibbs printf("ptregister: no getdev CCB, can't register device\n"); 26576babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 26676babe50SJustin T. Gibbs } 26776babe50SJustin T. Gibbs 26876babe50SJustin T. Gibbs softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 26976babe50SJustin T. Gibbs 27076babe50SJustin T. Gibbs if (softc == NULL) { 27176babe50SJustin T. Gibbs printf("daregister: Unable to probe new device. " 27276babe50SJustin T. Gibbs "Unable to allocate softc\n"); 27376babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 27476babe50SJustin T. Gibbs } 27576babe50SJustin T. Gibbs 27676babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 27776babe50SJustin T. Gibbs LIST_INIT(&softc->pending_ccbs); 27876babe50SJustin T. Gibbs softc->state = PT_STATE_NORMAL; 2798177437dSPoul-Henning Kamp bioq_init(&softc->bio_queue); 28076babe50SJustin T. Gibbs 2813ece1bd2SKenneth D. Merry softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 2823ece1bd2SKenneth D. Merry 28376babe50SJustin T. Gibbs periph->softc = softc; 28476babe50SJustin T. Gibbs 285b8b6b5d3SAlexander Motin bzero(&cpi, sizeof(cpi)); 286b8b6b5d3SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 287b8b6b5d3SAlexander Motin cpi.ccb_h.func_code = XPT_PATH_INQ; 288b8b6b5d3SAlexander Motin xpt_action((union ccb *)&cpi); 289b8b6b5d3SAlexander Motin 29085d92640SScott Long cam_periph_unlock(periph); 291a9d2245eSPoul-Henning Kamp softc->device_stats = devstat_new_entry("pt", 29276babe50SJustin T. Gibbs periph->unit_number, 0, 29376babe50SJustin T. Gibbs DEVSTAT_NO_BLOCKSIZE, 294b8b6b5d3SAlexander Motin SID_TYPE(&cgd->inq_data) | 295b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport), 2962a888f93SKenneth D. Merry DEVSTAT_PRIORITY_OTHER); 29776babe50SJustin T. Gibbs 29873d26919SKenneth D. Merry softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT, 29973d26919SKenneth D. Merry GID_OPERATOR, 0600, "%s%d", periph->periph_name, 30073d26919SKenneth D. Merry periph->unit_number); 30158b0b144SScott Long cam_periph_lock(periph); 302e2a5fdf9SNate Lawson softc->dev->si_drv1 = periph; 303e2a5fdf9SNate Lawson 30476babe50SJustin T. Gibbs /* 30576babe50SJustin T. Gibbs * Add async callbacks for bus reset and 30676babe50SJustin T. Gibbs * bus device reset calls. I don't bother 30776babe50SJustin T. Gibbs * checking if this fails as, in most cases, 30876babe50SJustin T. Gibbs * the system will function just fine without 30976babe50SJustin T. Gibbs * them and the only alternative would be to 31076babe50SJustin T. Gibbs * not attach the device on failure. 31176babe50SJustin T. Gibbs */ 31285d92640SScott Long xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, 31385d92640SScott Long ptasync, periph, periph->path); 31476babe50SJustin T. Gibbs 31576babe50SJustin T. Gibbs /* Tell the user we've attached to the device */ 31676babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 31776babe50SJustin T. Gibbs 31876babe50SJustin T. Gibbs return(CAM_REQ_CMP); 31976babe50SJustin T. Gibbs } 32076babe50SJustin T. Gibbs 32176babe50SJustin T. Gibbs static void 322ee9c90c7SKenneth D. Merry ptoninvalidate(struct cam_periph *periph) 323ee9c90c7SKenneth D. Merry { 324ee9c90c7SKenneth D. Merry struct pt_softc *softc; 325ee9c90c7SKenneth D. Merry 326ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc; 327ee9c90c7SKenneth D. Merry 328ee9c90c7SKenneth D. Merry /* 329ee9c90c7SKenneth D. Merry * De-register any async callbacks. 330ee9c90c7SKenneth D. Merry */ 33185d92640SScott Long xpt_register_async(0, ptasync, periph, periph->path); 332ee9c90c7SKenneth D. Merry 333ee9c90c7SKenneth D. Merry softc->flags |= PT_FLAG_DEVICE_INVALID; 334ee9c90c7SKenneth D. Merry 335ee9c90c7SKenneth D. Merry /* 336ee9c90c7SKenneth D. Merry * Return all queued I/O with ENXIO. 337ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 338ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 339ee9c90c7SKenneth D. Merry */ 340891619a6SPoul-Henning Kamp bioq_flush(&softc->bio_queue, NULL, ENXIO); 341ee9c90c7SKenneth D. Merry 342f0d9af51SMatt Jacob xpt_print(periph->path, "lost device\n"); 343ee9c90c7SKenneth D. Merry } 344ee9c90c7SKenneth D. Merry 345ee9c90c7SKenneth D. Merry static void 34676babe50SJustin T. Gibbs ptdtor(struct cam_periph *periph) 34776babe50SJustin T. Gibbs { 348ee9c90c7SKenneth D. Merry struct pt_softc *softc; 349ee9c90c7SKenneth D. Merry 350ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc; 351ee9c90c7SKenneth D. Merry 352f0d9af51SMatt Jacob xpt_print(periph->path, "removing device entry\n"); 3535f3fed85SEdward Tomasz Napierala devstat_remove_entry(softc->device_stats); 3545f3fed85SEdward Tomasz Napierala cam_periph_unlock(periph); 3555f3fed85SEdward Tomasz Napierala destroy_dev(softc->dev); 3565f3fed85SEdward Tomasz Napierala cam_periph_lock(periph); 357ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 35876babe50SJustin T. Gibbs } 35976babe50SJustin T. Gibbs 36076babe50SJustin T. Gibbs static void 36176babe50SJustin T. Gibbs ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 36276babe50SJustin T. Gibbs { 36376babe50SJustin T. Gibbs struct cam_periph *periph; 36476babe50SJustin T. Gibbs 36576babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 36676babe50SJustin T. Gibbs switch (code) { 36776babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 36876babe50SJustin T. Gibbs { 36976babe50SJustin T. Gibbs struct ccb_getdev *cgd; 37076babe50SJustin T. Gibbs cam_status status; 37176babe50SJustin T. Gibbs 37276babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 373c5ff3b2fSMatt Jacob if (cgd == NULL) 374c5ff3b2fSMatt Jacob break; 37576babe50SJustin T. Gibbs 37652c9ce25SScott Long if (cgd->protocol != PROTO_SCSI) 37752c9ce25SScott Long break; 37852c9ce25SScott Long 37910b6172aSMatt Jacob if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR) 38076babe50SJustin T. Gibbs break; 38176babe50SJustin T. Gibbs 38276babe50SJustin T. Gibbs /* 38376babe50SJustin T. Gibbs * Allocate a peripheral instance for 38476babe50SJustin T. Gibbs * this device and start the probe 38576babe50SJustin T. Gibbs * process. 38676babe50SJustin T. Gibbs */ 387ee9c90c7SKenneth D. Merry status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 388ee9c90c7SKenneth D. Merry ptstart, "pt", CAM_PERIPH_BIO, 389ee9c90c7SKenneth D. Merry cgd->ccb_h.path, ptasync, 390ee9c90c7SKenneth D. Merry AC_FOUND_DEVICE, cgd); 39176babe50SJustin T. Gibbs 39276babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 39376babe50SJustin T. Gibbs && status != CAM_REQ_INPROG) 39476babe50SJustin T. Gibbs printf("ptasync: Unable to attach to new device " 39576babe50SJustin T. Gibbs "due to status 0x%x\n", status); 39676babe50SJustin T. Gibbs break; 39776babe50SJustin T. Gibbs } 39876babe50SJustin T. Gibbs case AC_SENT_BDR: 39976babe50SJustin T. Gibbs case AC_BUS_RESET: 40076babe50SJustin T. Gibbs { 40176babe50SJustin T. Gibbs struct pt_softc *softc; 40276babe50SJustin T. Gibbs struct ccb_hdr *ccbh; 40376babe50SJustin T. Gibbs 40476babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 40576babe50SJustin T. Gibbs /* 40676babe50SJustin T. Gibbs * Don't fail on the expected unit attention 40776babe50SJustin T. Gibbs * that will occur. 40876babe50SJustin T. Gibbs */ 40976babe50SJustin T. Gibbs softc->flags |= PT_FLAG_RETRY_UA; 410fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 41176babe50SJustin T. Gibbs ccbh->ccb_state |= PT_CCB_RETRY_UA; 41276babe50SJustin T. Gibbs } 41307c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 41476babe50SJustin T. Gibbs default: 415516871c6SJustin T. Gibbs cam_periph_async(periph, code, path, arg); 41676babe50SJustin T. Gibbs break; 41776babe50SJustin T. Gibbs } 41876babe50SJustin T. Gibbs } 41976babe50SJustin T. Gibbs 42076babe50SJustin T. Gibbs static void 42176babe50SJustin T. Gibbs ptstart(struct cam_periph *periph, union ccb *start_ccb) 42276babe50SJustin T. Gibbs { 42376babe50SJustin T. Gibbs struct pt_softc *softc; 4248177437dSPoul-Henning Kamp struct bio *bp; 42576babe50SJustin T. Gibbs 42676babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 42776babe50SJustin T. Gibbs 428*fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n")); 429*fddde2b8SAlexander Motin 43076babe50SJustin T. Gibbs /* 43176babe50SJustin T. Gibbs * See if there is a buf with work for us to do.. 43276babe50SJustin T. Gibbs */ 4338177437dSPoul-Henning Kamp bp = bioq_first(&softc->bio_queue); 43476babe50SJustin T. Gibbs if (periph->immediate_priority <= periph->pinfo.priority) { 435*fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 43676babe50SJustin T. Gibbs ("queuing for immediate ccb\n")); 43776babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 43876babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 43976babe50SJustin T. Gibbs periph_links.sle); 44076babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 44176babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 44276babe50SJustin T. Gibbs } else if (bp == NULL) { 44376babe50SJustin T. Gibbs xpt_release_ccb(start_ccb); 44476babe50SJustin T. Gibbs } else { 4458177437dSPoul-Henning Kamp bioq_remove(&softc->bio_queue, bp); 44676babe50SJustin T. Gibbs 4471ecc485cSPoul-Henning Kamp devstat_start_transaction_bio(softc->device_stats, bp); 44876babe50SJustin T. Gibbs 44976babe50SJustin T. Gibbs scsi_send_receive(&start_ccb->csio, 45076babe50SJustin T. Gibbs /*retries*/4, 45176babe50SJustin T. Gibbs ptdone, 45276babe50SJustin T. Gibbs MSG_SIMPLE_Q_TAG, 4538177437dSPoul-Henning Kamp bp->bio_cmd == BIO_READ, 45476babe50SJustin T. Gibbs /*byte2*/0, 4558177437dSPoul-Henning Kamp bp->bio_bcount, 4568177437dSPoul-Henning Kamp bp->bio_data, 45776babe50SJustin T. Gibbs /*sense_len*/SSD_FULL_SIZE, 4583ece1bd2SKenneth D. Merry /*timeout*/softc->io_timeout); 45976babe50SJustin T. Gibbs 4609c6a0920SKenneth D. Merry start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA; 46176babe50SJustin T. Gibbs 46276babe50SJustin T. Gibbs /* 46376babe50SJustin T. Gibbs * Block out any asyncronous callbacks 46476babe50SJustin T. Gibbs * while we touch the pending ccb list. 46576babe50SJustin T. Gibbs */ 46676babe50SJustin T. Gibbs LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 46776babe50SJustin T. Gibbs periph_links.le); 46876babe50SJustin T. Gibbs 46976babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_bp = bp; 4708177437dSPoul-Henning Kamp bp = bioq_first(&softc->bio_queue); 47176babe50SJustin T. Gibbs 47276babe50SJustin T. Gibbs xpt_action(start_ccb); 47376babe50SJustin T. Gibbs 47476babe50SJustin T. Gibbs if (bp != NULL) { 47576babe50SJustin T. Gibbs /* Have more work to do, so ensure we stay scheduled */ 476bbfa4aa1SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 47776babe50SJustin T. Gibbs } 47876babe50SJustin T. Gibbs } 47976babe50SJustin T. Gibbs } 48076babe50SJustin T. Gibbs 48176babe50SJustin T. Gibbs static void 48276babe50SJustin T. Gibbs ptdone(struct cam_periph *periph, union ccb *done_ccb) 48376babe50SJustin T. Gibbs { 48476babe50SJustin T. Gibbs struct pt_softc *softc; 48576babe50SJustin T. Gibbs struct ccb_scsiio *csio; 48676babe50SJustin T. Gibbs 48776babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 488*fddde2b8SAlexander Motin 489*fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n")); 490*fddde2b8SAlexander Motin 49176babe50SJustin T. Gibbs csio = &done_ccb->csio; 49276babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_state) { 49376babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO: 49476babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO_UA: 49576babe50SJustin T. Gibbs { 4968177437dSPoul-Henning Kamp struct bio *bp; 49776babe50SJustin T. Gibbs 4988177437dSPoul-Henning Kamp bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 49976babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 50076babe50SJustin T. Gibbs int error; 50176babe50SJustin T. Gibbs int sf; 50276babe50SJustin T. Gibbs 50376babe50SJustin T. Gibbs if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 50476babe50SJustin T. Gibbs sf = SF_RETRY_UA; 50576babe50SJustin T. Gibbs else 50676babe50SJustin T. Gibbs sf = 0; 50776babe50SJustin T. Gibbs 5083393f8daSKenneth D. Merry error = pterror(done_ccb, CAM_RETRY_SELTO, sf); 5093393f8daSKenneth D. Merry if (error == ERESTART) { 51076babe50SJustin T. Gibbs /* 51176babe50SJustin T. Gibbs * A retry was scheuled, so 51276babe50SJustin T. Gibbs * just return. 51376babe50SJustin T. Gibbs */ 51476babe50SJustin T. Gibbs return; 51576babe50SJustin T. Gibbs } 51676babe50SJustin T. Gibbs if (error != 0) { 51776babe50SJustin T. Gibbs if (error == ENXIO) { 51876babe50SJustin T. Gibbs /* 51976babe50SJustin T. Gibbs * Catastrophic error. Mark our device 52076babe50SJustin T. Gibbs * as invalid. 52176babe50SJustin T. Gibbs */ 522f0d9af51SMatt Jacob xpt_print(periph->path, 523f0d9af51SMatt Jacob "Invalidating device\n"); 52476babe50SJustin T. Gibbs softc->flags |= PT_FLAG_DEVICE_INVALID; 52576babe50SJustin T. Gibbs } 52676babe50SJustin T. Gibbs 52776babe50SJustin T. Gibbs /* 52876babe50SJustin T. Gibbs * return all queued I/O with EIO, so that 52976babe50SJustin T. Gibbs * the client can retry these I/Os in the 53076babe50SJustin T. Gibbs * proper order should it attempt to recover. 53176babe50SJustin T. Gibbs */ 532891619a6SPoul-Henning Kamp bioq_flush(&softc->bio_queue, NULL, EIO); 5338177437dSPoul-Henning Kamp bp->bio_error = error; 5348177437dSPoul-Henning Kamp bp->bio_resid = bp->bio_bcount; 5358177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 53676babe50SJustin T. Gibbs } else { 5378177437dSPoul-Henning Kamp bp->bio_resid = csio->resid; 5388177437dSPoul-Henning Kamp bp->bio_error = 0; 5398177437dSPoul-Henning Kamp if (bp->bio_resid != 0) { 54076babe50SJustin T. Gibbs /* Short transfer ??? */ 5418177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 54276babe50SJustin T. Gibbs } 54376babe50SJustin T. Gibbs } 54476babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 54576babe50SJustin T. Gibbs cam_release_devq(done_ccb->ccb_h.path, 54676babe50SJustin T. Gibbs /*relsim_flags*/0, 54776babe50SJustin T. Gibbs /*reduction*/0, 54876babe50SJustin T. Gibbs /*timeout*/0, 54976babe50SJustin T. Gibbs /*getcount_only*/0); 55076babe50SJustin T. Gibbs } else { 5518177437dSPoul-Henning Kamp bp->bio_resid = csio->resid; 5528177437dSPoul-Henning Kamp if (bp->bio_resid != 0) 5538177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR; 55476babe50SJustin T. Gibbs } 55576babe50SJustin T. Gibbs 55676babe50SJustin T. Gibbs /* 55776babe50SJustin T. Gibbs * Block out any asyncronous callbacks 55876babe50SJustin T. Gibbs * while we touch the pending ccb list. 55976babe50SJustin T. Gibbs */ 56076babe50SJustin T. Gibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 56176babe50SJustin T. Gibbs 562a9d2245eSPoul-Henning Kamp biofinish(bp, softc->device_stats, 0); 56376babe50SJustin T. Gibbs break; 56476babe50SJustin T. Gibbs } 56576babe50SJustin T. Gibbs case PT_CCB_WAITING: 56676babe50SJustin T. Gibbs /* Caller will release the CCB */ 56776babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 56876babe50SJustin T. Gibbs return; 56976babe50SJustin T. Gibbs } 57076babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 57176babe50SJustin T. Gibbs } 57276babe50SJustin T. Gibbs 57376babe50SJustin T. Gibbs static int 57476babe50SJustin T. Gibbs pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 57576babe50SJustin T. Gibbs { 57676babe50SJustin T. Gibbs struct pt_softc *softc; 57776babe50SJustin T. Gibbs struct cam_periph *periph; 57876babe50SJustin T. Gibbs 57976babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 58076babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 58176babe50SJustin T. Gibbs 58276babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 58376babe50SJustin T. Gibbs &softc->saved_ccb)); 58476babe50SJustin T. Gibbs } 58576babe50SJustin T. Gibbs 5863ece1bd2SKenneth D. Merry static int 58789c9c53dSPoul-Henning Kamp ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 5883ece1bd2SKenneth D. Merry { 5893ece1bd2SKenneth D. Merry struct cam_periph *periph; 5903ece1bd2SKenneth D. Merry struct pt_softc *softc; 5912b83592fSScott Long int error = 0; 5923ece1bd2SKenneth D. Merry 593e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 5943ece1bd2SKenneth D. Merry if (periph == NULL) 5953ece1bd2SKenneth D. Merry return(ENXIO); 5963ece1bd2SKenneth D. Merry 5973ece1bd2SKenneth D. Merry softc = (struct pt_softc *)periph->softc; 5983ece1bd2SKenneth D. Merry 5992b83592fSScott Long cam_periph_lock(periph); 6003ece1bd2SKenneth D. Merry 6013ece1bd2SKenneth D. Merry switch(cmd) { 6023ece1bd2SKenneth D. Merry case PTIOCGETTIMEOUT: 6033ece1bd2SKenneth D. Merry if (softc->io_timeout >= 1000) 6043ece1bd2SKenneth D. Merry *(int *)addr = softc->io_timeout / 1000; 6053ece1bd2SKenneth D. Merry else 6063ece1bd2SKenneth D. Merry *(int *)addr = 0; 6073ece1bd2SKenneth D. Merry break; 6083ece1bd2SKenneth D. Merry case PTIOCSETTIMEOUT: 6093ece1bd2SKenneth D. Merry if (*(int *)addr < 1) { 6103ece1bd2SKenneth D. Merry error = EINVAL; 6113ece1bd2SKenneth D. Merry break; 6123ece1bd2SKenneth D. Merry } 6133ece1bd2SKenneth D. Merry 6143ece1bd2SKenneth D. Merry softc->io_timeout = *(int *)addr * 1000; 6153ece1bd2SKenneth D. Merry 6163ece1bd2SKenneth D. Merry break; 6173ece1bd2SKenneth D. Merry default: 6183ece1bd2SKenneth D. Merry error = cam_periph_ioctl(periph, cmd, addr, pterror); 6193ece1bd2SKenneth D. Merry break; 6203ece1bd2SKenneth D. Merry } 6213ece1bd2SKenneth D. Merry 6223ece1bd2SKenneth D. Merry cam_periph_unlock(periph); 6233ece1bd2SKenneth D. Merry 6243ece1bd2SKenneth D. Merry return(error); 6253ece1bd2SKenneth D. Merry } 6263ece1bd2SKenneth D. Merry 62776babe50SJustin T. Gibbs void 62876babe50SJustin T. Gibbs scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 62976babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 63076babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2, 63176babe50SJustin T. Gibbs u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 63276babe50SJustin T. Gibbs u_int32_t timeout) 63376babe50SJustin T. Gibbs { 63476babe50SJustin T. Gibbs struct scsi_send_receive *scsi_cmd; 63576babe50SJustin T. Gibbs 63676babe50SJustin T. Gibbs scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 63776babe50SJustin T. Gibbs scsi_cmd->opcode = readop ? RECEIVE : SEND; 63876babe50SJustin T. Gibbs scsi_cmd->byte2 = byte2; 63976babe50SJustin T. Gibbs scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 64076babe50SJustin T. Gibbs scsi_cmd->control = 0; 64176babe50SJustin T. Gibbs 64276babe50SJustin T. Gibbs cam_fill_csio(csio, 64376babe50SJustin T. Gibbs retries, 64476babe50SJustin T. Gibbs cbfcnp, 64576babe50SJustin T. Gibbs /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 64676babe50SJustin T. Gibbs tag_action, 64776babe50SJustin T. Gibbs data_ptr, 64876babe50SJustin T. Gibbs xfer_len, 64976babe50SJustin T. Gibbs sense_len, 65076babe50SJustin T. Gibbs sizeof(*scsi_cmd), 65176babe50SJustin T. Gibbs timeout); 65276babe50SJustin T. Gibbs } 653