vpo.c revision 312850
118334Speter/*- 2169689Skan * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 3169689Skan * All rights reserved. 418334Speter * 590075Sobrien * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer. 1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1290075Sobrien * documentation and/or other materials provided with the distribution. 1390075Sobrien * 1490075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1718334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2218334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350397Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24132718Skan * SUCH DAMAGE. 25132718Skan * 2650397Sobrien */ 2718334Speter 2818334Speter#include <sys/cdefs.h> 2990075Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/ppbus/vpo.c 312850 2017-01-26 21:35:58Z mav $"); 3018334Speter 3150397Sobrien#include <sys/param.h> 3250397Sobrien#include <sys/systm.h> 3390075Sobrien#include <sys/module.h> 3496263Sobrien#include <sys/bus.h> 3590075Sobrien#include <sys/lock.h> 3690075Sobrien#include <sys/mutex.h> 37169689Skan#include <sys/malloc.h> 38169689Skan 39169689Skan#include <cam/cam.h> 40169689Skan#include <cam/cam_ccb.h> 4118334Speter#include <cam/cam_sim.h> 42169689Skan#include <cam/cam_xpt_sim.h> 43169689Skan#include <cam/cam_debug.h> 44169689Skan#include <cam/cam_periph.h> 45169689Skan 4618334Speter#include <cam/scsi/scsi_all.h> 47117395Skan#include <cam/scsi/scsi_message.h> 4852284Sobrien#include <cam/scsi/scsi_da.h> 49169689Skan 50169689Skan#include <sys/kernel.h> 5152284Sobrien 5252284Sobrien#include "opt_vpo.h" 5318334Speter 54117395Skan#include <dev/ppbus/ppbconf.h> 5552284Sobrien#include <dev/ppbus/vpoio.h> 56117395Skan 57132718Skan#include "ppbus_if.h" 58117395Skan 59117395Skanstruct vpo_sense { 6090075Sobrien struct scsi_sense cmd; 61169689Skan unsigned int stat; 62169689Skan unsigned int count; 6390075Sobrien}; 6490075Sobrien 6596263Sobrienstruct vpo_data { 66169689Skan device_t vpo_dev; 67169689Skan int vpo_stat; 68169689Skan int vpo_count; 6952284Sobrien int vpo_error; 70132718Skan 71132718Skan int vpo_isplus; 7290075Sobrien 7352284Sobrien struct cam_sim *sim; 7490075Sobrien 75132718Skan struct vpo_sense vpo_sense; 7652284Sobrien 77169689Skan struct vpoio_data vpo_io; /* interface to low level functions */ 7852284Sobrien}; 79169689Skan 8052284Sobrien#define DEVTOSOFTC(dev) \ 81169689Skan ((struct vpo_data *)device_get_softc(dev)) 82169689Skan 83169689Skan/* cam related functions */ 8452284Sobrienstatic void vpo_action(struct cam_sim *sim, union ccb *ccb); 85169689Skanstatic void vpo_poll(struct cam_sim *sim); 86169689Skan 87169689Skanstatic void 88169689Skanvpo_identify(driver_t *driver, device_t parent) 89169689Skan{ 90169689Skan 91169689Skan device_t dev; 92169689Skan 93169689Skan dev = device_find_child(parent, "vpo", -1); 9452284Sobrien if (!dev) 9552284Sobrien BUS_ADD_CHILD(parent, 0, "vpo", -1); 9652284Sobrien} 9790075Sobrien 98132718Skan/* 9952284Sobrien * vpo_probe() 10052284Sobrien */ 101169689Skanstatic int 10252284Sobrienvpo_probe(device_t dev) 103169689Skan{ 10452284Sobrien device_t ppbus = device_get_parent(dev); 10552284Sobrien struct vpo_data *vpo; 10652284Sobrien int error; 10752284Sobrien 10852284Sobrien vpo = DEVTOSOFTC(dev); 10952284Sobrien vpo->vpo_dev = dev; 11052284Sobrien 11152284Sobrien /* check ZIP before ZIP+ or imm_probe() will send controls to 11252284Sobrien * the printer or whatelse connected to the port */ 11352284Sobrien ppb_lock(ppbus); 11452284Sobrien if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) { 11552284Sobrien vpo->vpo_isplus = 0; 116169689Skan device_set_desc(dev, 117169689Skan "Iomega VPI0 Parallel to SCSI interface"); 11852284Sobrien } else if ((error = imm_probe(dev, &vpo->vpo_io)) == 0) { 11952284Sobrien vpo->vpo_isplus = 1; 12052284Sobrien device_set_desc(dev, 121169689Skan "Iomega Matchmaker Parallel to SCSI interface"); 12252284Sobrien } else { 123169689Skan ppb_unlock(ppbus); 12452284Sobrien return (error); 125169689Skan } 12652284Sobrien ppb_unlock(ppbus); 12790075Sobrien 12890075Sobrien return (0); 12990075Sobrien} 130169689Skan 13190075Sobrien/* 132169689Skan * vpo_attach() 13352284Sobrien */ 13452284Sobrienstatic int 13590075Sobrienvpo_attach(device_t dev) 13690075Sobrien{ 137169689Skan struct vpo_data *vpo = DEVTOSOFTC(dev); 138169689Skan device_t ppbus = device_get_parent(dev); 13990075Sobrien struct ppb_data *ppb = device_get_softc(ppbus); /* XXX: layering */ 140169689Skan struct cam_devq *devq; 14190075Sobrien int error; 14290075Sobrien 14390075Sobrien /* low level attachment */ 14490075Sobrien if (vpo->vpo_isplus) { 145169689Skan if ((error = imm_attach(&vpo->vpo_io))) 14618334Speter return (error); 14790075Sobrien } else { 14890075Sobrien if ((error = vpoio_attach(&vpo->vpo_io))) 14990075Sobrien return (error); 15090075Sobrien } 15118334Speter 152169689Skan /* 153169689Skan ** Now tell the generic SCSI layer 15490075Sobrien ** about our bus. 155169689Skan */ 15690075Sobrien devq = cam_simq_alloc(/*maxopenings*/1); 15718334Speter /* XXX What about low-level detach on error? */ 15890075Sobrien if (devq == NULL) 159169689Skan return (ENXIO); 16018334Speter 16190075Sobrien vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, 16252284Sobrien device_get_unit(dev), ppb->ppc_lock, 163169689Skan /*untagged*/1, /*tagged*/0, devq); 164169689Skan if (vpo->sim == NULL) { 16590075Sobrien cam_simq_free(devq); 16690075Sobrien return (ENXIO); 167169689Skan } 168169689Skan 16952284Sobrien ppb_lock(ppbus); 17090075Sobrien if (xpt_bus_register(vpo->sim, dev, /*bus*/0) != CAM_SUCCESS) { 17118334Speter cam_sim_free(vpo->sim, /*free_devq*/TRUE); 172169689Skan ppb_unlock(ppbus); 173169689Skan return (ENXIO); 17490075Sobrien } 175169689Skan ppb_unlock(ppbus); 17690075Sobrien 17718334Speter return (0); 17890075Sobrien} 17990075Sobrien 18090075Sobrien/* 18190075Sobrien * vpo_intr() 18290075Sobrien */ 18352284Sobrienstatic void 184169689Skanvpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) 18518334Speter{ 186169689Skan int errno; /* error in errno.h */ 18752284Sobrien#ifdef VP0_DEBUG 188169689Skan int i; 189169689Skan#endif 19052284Sobrien uint8_t *ptr; 19190075Sobrien 19252284Sobrien ptr = scsiio_cdb_ptr(csio); 193169689Skan if (vpo->vpo_isplus) { 19490075Sobrien errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 195169689Skan csio->ccb_h.target_id, 196169689Skan ptr, csio->cdb_len, 197169689Skan (char *)csio->data_ptr, csio->dxfer_len, 198169689Skan &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error); 199169689Skan } else { 20090075Sobrien errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 201169689Skan csio->ccb_h.target_id, 202169689Skan ptr, csio->cdb_len, 20318334Speter (char *)csio->data_ptr, csio->dxfer_len, 20418334Speter &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error); 20590075Sobrien } 20690075Sobrien 20790075Sobrien#ifdef VP0_DEBUG 20890075Sobrien printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 20990075Sobrien errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error); 210169689Skan 21152284Sobrien /* dump of command */ 212169689Skan for (i=0; i<csio->cdb_len; i++) 213169689Skan printf("%x ", ((char *)ptr)[i]); 21452284Sobrien 215169689Skan printf("\n"); 216169689Skan#endif 217169689Skan 21890075Sobrien if (errno) { 21990075Sobrien /* connection to ppbus interrupted */ 22090075Sobrien csio->ccb_h.status = CAM_CMD_TIMEOUT; 22190075Sobrien return; 22290075Sobrien } 22390075Sobrien 22490075Sobrien /* if a timeout occured, no sense */ 22590075Sobrien if (vpo->vpo_error) { 22690075Sobrien if (vpo->vpo_error != VP0_ESELECT_TIMEOUT) 22790075Sobrien device_printf(vpo->vpo_dev, "VP0 error/timeout (%d)\n", 22890075Sobrien vpo->vpo_error); 229169689Skan 230169689Skan csio->ccb_h.status = CAM_CMD_TIMEOUT; 231169689Skan return; 232169689Skan } 233169689Skan 234169689Skan /* check scsi status */ 23590075Sobrien if (vpo->vpo_stat != SCSI_STATUS_OK) { 23690075Sobrien csio->scsi_status = vpo->vpo_stat; 23790075Sobrien 23818334Speter /* check if we have to sense the drive */ 23990075Sobrien if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) { 24090075Sobrien 24190075Sobrien vpo->vpo_sense.cmd.opcode = REQUEST_SENSE; 24290075Sobrien vpo->vpo_sense.cmd.length = csio->sense_len; 243169689Skan vpo->vpo_sense.cmd.control = 0; 24490075Sobrien 24590075Sobrien if (vpo->vpo_isplus) { 24690075Sobrien errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 24718334Speter csio->ccb_h.target_id, 248117395Skan (char *)&vpo->vpo_sense.cmd, 249117395Skan sizeof(vpo->vpo_sense.cmd), 25090075Sobrien (char *)&csio->sense_data, csio->sense_len, 251132718Skan &vpo->vpo_sense.stat, &vpo->vpo_sense.count, 252132718Skan &vpo->vpo_error); 25352284Sobrien } else { 25496263Sobrien errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 255132718Skan csio->ccb_h.target_id, 25696263Sobrien (char *)&vpo->vpo_sense.cmd, 25796263Sobrien sizeof(vpo->vpo_sense.cmd), 258102780Skan (char *)&csio->sense_data, csio->sense_len, 259102780Skan &vpo->vpo_sense.stat, &vpo->vpo_sense.count, 260102780Skan &vpo->vpo_error); 261102780Skan } 262102780Skan 263102780Skan 264102780Skan#ifdef VP0_DEBUG 265102780Skan printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 26696263Sobrien errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error); 267132718Skan#endif 26896263Sobrien 269169689Skan /* check sense return status */ 270169689Skan if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) { 27196263Sobrien /* sense ok */ 27296263Sobrien csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR; 27396263Sobrien csio->sense_resid = csio->sense_len - vpo->vpo_sense.count; 27496263Sobrien 27596263Sobrien#ifdef VP0_DEBUG 276132718Skan /* dump of sense info */ 27796263Sobrien printf("(sense) "); 27896263Sobrien for (i=0; i<vpo->vpo_sense.count; i++) 27996263Sobrien printf("%x ", ((char *)&csio->sense_data)[i]); 280119256Skan printf("\n"); 281119256Skan#endif 282119256Skan 283119256Skan } else { 28496263Sobrien /* sense failed */ 285119256Skan csio->ccb_h.status = CAM_AUTOSENSE_FAIL; 286119256Skan } 287119256Skan } else { 288119256Skan /* no sense */ 289119256Skan csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; 290119256Skan } 291169689Skan 292119256Skan return; 293119256Skan } 29496263Sobrien 295119256Skan csio->resid = csio->dxfer_len - vpo->vpo_count; 296119256Skan csio->ccb_h.status = CAM_REQ_CMP; 29796263Sobrien} 29896263Sobrien 29996263Sobrienstatic void 30096263Sobrienvpo_action(struct cam_sim *sim, union ccb *ccb) 30196263Sobrien{ 30296263Sobrien struct vpo_data *vpo = (struct vpo_data *)sim->softc; 30396263Sobrien 30496263Sobrien ppb_assert_locked(device_get_parent(vpo->vpo_dev)); 30596263Sobrien switch (ccb->ccb_h.func_code) { 306169689Skan case XPT_SCSI_IO: 307169689Skan { 308169689Skan struct ccb_scsiio *csio; 309169689Skan 310169689Skan csio = &ccb->csio; 311169689Skan 312169689Skan if (ccb->ccb_h.flags & CAM_CDB_PHYS) { 313169689Skan ccb->ccb_h.status = CAM_REQ_INVALID; 314169689Skan xpt_done(ccb); 315169689Skan break; 316169689Skan } 317169689Skan#ifdef VP0_DEBUG 318169689Skan device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n", 319169689Skan scsiio_cdb_ptr(csio)); 320169689Skan#endif 321169689Skan vpo_intr(vpo, csio); 322169689Skan 323169689Skan xpt_done(ccb); 324169689Skan 325169689Skan break; 326169689Skan } 327169689Skan case XPT_CALC_GEOMETRY: 328169689Skan { 329169689Skan struct ccb_calc_geometry *ccg; 330169689Skan 331169689Skan ccg = &ccb->ccg; 332169689Skan 33390075Sobrien#ifdef VP0_DEBUG 33490075Sobrien device_printf(vpo->vpo_dev, "XPT_CALC_GEOMETRY (bs=%d,vs=%jd,c=%d,h=%d,spt=%d) request\n", 335169689Skan ccg->block_size, 33690075Sobrien (intmax_t)ccg->volume_size, 33796263Sobrien ccg->cylinders, 33890075Sobrien ccg->heads, 33952284Sobrien ccg->secs_per_track); 34090075Sobrien#endif 34152284Sobrien 342169689Skan ccg->heads = 64; 34390075Sobrien ccg->secs_per_track = 32; 344169689Skan ccg->cylinders = ccg->volume_size / 34590075Sobrien (ccg->heads * ccg->secs_per_track); 34690075Sobrien 347169689Skan ccb->ccb_h.status = CAM_REQ_CMP; 34890075Sobrien xpt_done(ccb); 349169689Skan break; 35090075Sobrien } 35190075Sobrien case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 352169689Skan { 35352284Sobrien 35496263Sobrien#ifdef VP0_DEBUG 355169689Skan device_printf(vpo->vpo_dev, "XPT_RESET_BUS request\n"); 356102780Skan#endif 357102780Skan 358102780Skan if (vpo->vpo_isplus) { 359102780Skan if (imm_reset_bus(&vpo->vpo_io)) { 360102780Skan ccb->ccb_h.status = CAM_REQ_CMP_ERR; 36196263Sobrien xpt_done(ccb); 36296263Sobrien return; 36390075Sobrien } 36496263Sobrien } else { 36596263Sobrien if (vpoio_reset_bus(&vpo->vpo_io)) { 366169689Skan ccb->ccb_h.status = CAM_REQ_CMP_ERR; 36796263Sobrien xpt_done(ccb); 36896263Sobrien return; 369169689Skan } 370169689Skan } 371169689Skan 372169689Skan ccb->ccb_h.status = CAM_REQ_CMP; 373169689Skan xpt_done(ccb); 37496263Sobrien break; 37596263Sobrien } 376169689Skan case XPT_PATH_INQ: /* Path routing inquiry */ 377169689Skan { 378169689Skan struct ccb_pathinq *cpi = &ccb->cpi; 379169689Skan 380169689Skan#ifdef VP0_DEBUG 381169689Skan device_printf(vpo->vpo_dev, "XPT_PATH_INQ request\n"); 382169689Skan#endif 383169689Skan cpi->version_num = 1; /* XXX??? */ 384169689Skan cpi->hba_inquiry = 0; 385169689Skan cpi->target_sprt = 0; 386169689Skan cpi->hba_misc = 0; 387169689Skan cpi->hba_eng_cnt = 0; 388169689Skan cpi->max_target = 7; 389169689Skan cpi->max_lun = 0; 390169689Skan cpi->initiator_id = VP0_INITIATOR; 391169689Skan cpi->bus_id = sim->bus_id; 392169689Skan cpi->base_transfer_speed = 93; 393169689Skan strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 394169689Skan strncpy(cpi->hba_vid, "Iomega", HBA_IDLEN); 395169689Skan strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 396169689Skan cpi->unit_number = sim->unit_number; 397169689Skan cpi->transport = XPORT_PPB; 398169689Skan cpi->transport_version = 0; 399169689Skan 400169689Skan cpi->ccb_h.status = CAM_REQ_CMP; 401169689Skan xpt_done(ccb); 402169689Skan break; 403169689Skan } 404169689Skan default: 405169689Skan ccb->ccb_h.status = CAM_REQ_INVALID; 406169689Skan xpt_done(ccb); 407169689Skan break; 408117395Skan } 409117395Skan 410132718Skan return; 41196263Sobrien} 412169689Skan 41396263Sobrienstatic void 414169689Skanvpo_poll(struct cam_sim *sim) 41596263Sobrien{ 41696263Sobrien 41796263Sobrien /* The ZIP is actually always polled throw vpo_action(). */ 41896263Sobrien} 419169689Skan 420169689Skanstatic devclass_t vpo_devclass; 421169689Skan 422169689Skanstatic device_method_t vpo_methods[] = { 423169689Skan /* device interface */ 424169689Skan DEVMETHOD(device_identify, vpo_identify), 425169689Skan DEVMETHOD(device_probe, vpo_probe), 426169689Skan DEVMETHOD(device_attach, vpo_attach), 427169689Skan 42896263Sobrien { 0, 0 } 429169689Skan}; 430169689Skan 431169689Skanstatic driver_t vpo_driver = { 43296263Sobrien "vpo", 43396263Sobrien vpo_methods, 43496263Sobrien sizeof(struct vpo_data), 43596263Sobrien}; 436169689SkanDRIVER_MODULE(vpo, ppbus, vpo_driver, vpo_devclass, 0, 0); 437169689SkanMODULE_DEPEND(vpo, ppbus, 1, 1, 1); 438169689SkanMODULE_DEPEND(vpo, cam, 1, 1, 1); 439169689Skan