vpo.c revision 56455
128219Smsmith/*- 255939Snsouch * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 328219Smsmith * All rights reserved. 428219Smsmith * 528219Smsmith * Redistribution and use in source and binary forms, with or without 628219Smsmith * modification, are permitted provided that the following conditions 728219Smsmith * are met: 828219Smsmith * 1. Redistributions of source code must retain the above copyright 928219Smsmith * notice, this list of conditions and the following disclaimer. 1028219Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1128219Smsmith * notice, this list of conditions and the following disclaimer in the 1228219Smsmith * documentation and/or other materials provided with the distribution. 1328219Smsmith * 1428219Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1528219Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1628219Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1728219Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1828219Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1928219Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2028219Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2128219Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2228219Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2328219Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2428219Smsmith * SUCH DAMAGE. 2528219Smsmith * 2650477Speter * $FreeBSD: head/sys/dev/ppbus/vpo.c 56455 2000-01-23 14:41:04Z peter $ 2728219Smsmith */ 2828219Smsmith 2928219Smsmith#include <sys/param.h> 3028219Smsmith#include <sys/systm.h> 3155939Snsouch#include <sys/module.h> 3255939Snsouch#include <sys/bus.h> 3328219Smsmith 3428219Smsmith#include <machine/clock.h> 3528219Smsmith 3639520Snsouch#include <cam/cam.h> 3739520Snsouch#include <cam/cam_ccb.h> 3839520Snsouch#include <cam/cam_sim.h> 3939520Snsouch#include <cam/cam_xpt_sim.h> 4039520Snsouch#include <cam/cam_debug.h> 4139520Snsouch 4239520Snsouch#include <cam/scsi/scsi_all.h> 4339520Snsouch#include <cam/scsi/scsi_message.h> 4439520Snsouch#include <cam/scsi/scsi_da.h> 4539520Snsouch 4628219Smsmith#include <sys/kernel.h> 4728219Smsmith 4842475Snsouch#include "opt_vpo.h" 4942475Snsouch 5028219Smsmith#include <dev/ppbus/ppbconf.h> 5138061Smsmith#include <dev/ppbus/vpoio.h> 5228219Smsmith 5355939Snsouch#include "ppbus_if.h" 5455939Snsouch 5538061Smsmithstruct vpo_sense { 5638061Smsmith struct scsi_sense cmd; 5738061Smsmith unsigned int stat; 5838061Smsmith unsigned int count; 5938061Smsmith}; 6028219Smsmith 6138061Smsmithstruct vpo_data { 6238061Smsmith unsigned short vpo_unit; 6328219Smsmith 6438061Smsmith int vpo_stat; 6538061Smsmith int vpo_count; 6638061Smsmith int vpo_error; 6728219Smsmith 6839134Snsouch int vpo_isplus; 6939134Snsouch 7039520Snsouch struct cam_sim *sim; 7139520Snsouch struct cam_path *path; 7239520Snsouch 7338061Smsmith struct vpo_sense vpo_sense; 7438061Smsmith 7538061Smsmith struct vpoio_data vpo_io; /* interface to low level functions */ 7638061Smsmith}; 7738061Smsmith 7855939Snsouch#define DEVTOSOFTC(dev) \ 7955939Snsouch ((struct vpo_data *)device_get_softc(dev)) 8028219Smsmith 8155939Snsouch/* cam related functions */ 8255939Snsouchstatic void vpo_action(struct cam_sim *sim, union ccb *ccb); 8355939Snsouchstatic void vpo_poll(struct cam_sim *sim); 8455939Snsouch 8556455Speterstatic void 8656455Spetervpo_identify(driver_t *driver, device_t parent) 8756455Speter{ 8856455Speter 8956455Speter BUS_ADD_CHILD(parent, 0, "vpo", 0); 9056455Speter} 9156455Speter 9228219Smsmith/* 9355939Snsouch * vpo_probe() 9428219Smsmith */ 9555939Snsouchstatic int 9655939Snsouchvpo_probe(device_t dev) 9728219Smsmith{ 9828219Smsmith struct vpo_data *vpo; 9955939Snsouch int error; 10028219Smsmith 10155939Snsouch vpo = DEVTOSOFTC(dev); 10228219Smsmith bzero(vpo, sizeof(struct vpo_data)); 10328219Smsmith 10428219Smsmith /* vpo dependent initialisation */ 10555939Snsouch vpo->vpo_unit = device_get_unit(dev); 10628219Smsmith 10738061Smsmith /* low level probe */ 10838061Smsmith vpoio_set_unit(&vpo->vpo_io, vpo->vpo_unit); 10938061Smsmith 11039520Snsouch /* check ZIP before ZIP+ or imm_probe() will send controls to 11139520Snsouch * the printer or whatelse connected to the port */ 11255939Snsouch if ((error = vpoio_probe(dev, &vpo->vpo_io)) == 0) { 11339520Snsouch vpo->vpo_isplus = 0; 11455939Snsouch device_set_desc(dev, 11555939Snsouch "Iomega VPI0 Parallel to SCSI interface"); 11655939Snsouch } else if ((error = imm_probe(dev, &vpo->vpo_io)) == 0) { 11739134Snsouch vpo->vpo_isplus = 1; 11855939Snsouch device_set_desc(dev, 11955939Snsouch "Iomega Matchmaker Parallel to SCSI interface"); 12039520Snsouch } else { 12155939Snsouch return (error); 12228219Smsmith } 12328219Smsmith 12455939Snsouch return (0); 12528219Smsmith} 12628219Smsmith 12728219Smsmith/* 12855939Snsouch * vpo_attach() 12928219Smsmith */ 13028219Smsmithstatic int 13155939Snsouchvpo_attach(device_t dev) 13228219Smsmith{ 13355939Snsouch struct vpo_data *vpo = DEVTOSOFTC(dev); 13439520Snsouch struct cam_devq *devq; 13555939Snsouch int error; 13628219Smsmith 13738061Smsmith /* low level attachment */ 13839134Snsouch if (vpo->vpo_isplus) { 13955939Snsouch if ((error = imm_attach(&vpo->vpo_io))) 14055939Snsouch return (error); 14139134Snsouch } else { 14255939Snsouch if ((error = vpoio_attach(&vpo->vpo_io))) 14355939Snsouch return (error); 14439134Snsouch } 14538061Smsmith 14628219Smsmith /* 14739520Snsouch ** Now tell the generic SCSI layer 14839520Snsouch ** about our bus. 14939520Snsouch */ 15039520Snsouch devq = cam_simq_alloc(/*maxopenings*/1); 15139520Snsouch /* XXX What about low-level detach on error? */ 15239520Snsouch if (devq == NULL) 15355939Snsouch return (ENXIO); 15428219Smsmith 15555939Snsouch vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, 15655939Snsouch device_get_unit(dev), 15739520Snsouch /*untagged*/1, /*tagged*/0, devq); 15839520Snsouch if (vpo->sim == NULL) { 15939520Snsouch cam_simq_free(devq); 16055939Snsouch return (ENXIO); 16139520Snsouch } 16238061Smsmith 16339520Snsouch if (xpt_bus_register(vpo->sim, /*bus*/0) != CAM_SUCCESS) { 16439520Snsouch cam_sim_free(vpo->sim, /*free_devq*/TRUE); 16555939Snsouch return (ENXIO); 16639520Snsouch } 16728219Smsmith 16839520Snsouch if (xpt_create_path(&vpo->path, /*periph*/NULL, 16939520Snsouch cam_sim_path(vpo->sim), CAM_TARGET_WILDCARD, 17039520Snsouch CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 17139520Snsouch xpt_bus_deregister(cam_sim_path(vpo->sim)); 17239520Snsouch cam_sim_free(vpo->sim, /*free_devq*/TRUE); 17355939Snsouch return (ENXIO); 17439520Snsouch } 17528219Smsmith 17639520Snsouch /* all went ok */ 17728219Smsmith 17855939Snsouch return (0); 17928219Smsmith} 18028219Smsmith 18128219Smsmith/* 18238061Smsmith * vpo_intr() 18328219Smsmith */ 18438061Smsmithstatic void 18539520Snsouchvpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio) 18628219Smsmith{ 18741591Sarchie int errno; /* error in errno.h */ 18839520Snsouch int s; 18941591Sarchie#ifdef VP0_DEBUG 19041591Sarchie int i; 19141591Sarchie#endif 19228219Smsmith 19339520Snsouch s = splcam(); 19428219Smsmith 19539134Snsouch if (vpo->vpo_isplus) { 19639134Snsouch errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 19739520Snsouch csio->ccb_h.target_id, 19839520Snsouch (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len, 19939520Snsouch (char *)csio->data_ptr, csio->dxfer_len, 20039520Snsouch &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error); 20139134Snsouch } else { 20239134Snsouch errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 20339520Snsouch csio->ccb_h.target_id, 20439520Snsouch (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len, 20539520Snsouch (char *)csio->data_ptr, csio->dxfer_len, 20639520Snsouch &vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error); 20739134Snsouch } 20828219Smsmith 20928257Smsmith#ifdef VP0_DEBUG 21028257Smsmith printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 21128257Smsmith errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error); 21239520Snsouch 21339520Snsouch /* dump of command */ 21439520Snsouch for (i=0; i<csio->cdb_len; i++) 21539520Snsouch printf("%x ", ((char *)&csio->cdb_io.cdb_bytes)[i]); 21639520Snsouch 21739520Snsouch printf("\n"); 21828257Smsmith#endif 21928257Smsmith 22028257Smsmith if (errno) { 22128257Smsmith /* connection to ppbus interrupted */ 22239520Snsouch csio->ccb_h.status = CAM_CMD_TIMEOUT; 22328257Smsmith goto error; 22428257Smsmith } 22528219Smsmith 22628257Smsmith /* if a timeout occured, no sense */ 22728257Smsmith if (vpo->vpo_error) { 22839520Snsouch if (vpo->vpo_error != VP0_ESELECT_TIMEOUT) 22939520Snsouch printf("vpo%d: VP0 error/timeout (%d)\n", 23039520Snsouch vpo->vpo_unit, vpo->vpo_error); 23139520Snsouch 23239520Snsouch csio->ccb_h.status = CAM_CMD_TIMEOUT; 23328257Smsmith goto error; 23428257Smsmith } 23528219Smsmith 23639520Snsouch /* check scsi status */ 23739520Snsouch if (vpo->vpo_stat != SCSI_STATUS_OK) { 23839520Snsouch csio->scsi_status = vpo->vpo_stat; 23928219Smsmith 24039520Snsouch /* check if we have to sense the drive */ 24139520Snsouch if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) { 24228219Smsmith 24339520Snsouch vpo->vpo_sense.cmd.opcode = REQUEST_SENSE; 24439520Snsouch vpo->vpo_sense.cmd.length = csio->sense_len; 24528219Smsmith vpo->vpo_sense.cmd.control = 0; 24628219Smsmith 24739134Snsouch if (vpo->vpo_isplus) { 24839134Snsouch errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 24939520Snsouch csio->ccb_h.target_id, 25039134Snsouch (char *)&vpo->vpo_sense.cmd, 25139134Snsouch sizeof(vpo->vpo_sense.cmd), 25239520Snsouch (char *)&csio->sense_data, csio->sense_len, 25339134Snsouch &vpo->vpo_sense.stat, &vpo->vpo_sense.count, 25439134Snsouch &vpo->vpo_error); 25539134Snsouch } else { 25639134Snsouch errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR, 25739520Snsouch csio->ccb_h.target_id, 25839134Snsouch (char *)&vpo->vpo_sense.cmd, 25939134Snsouch sizeof(vpo->vpo_sense.cmd), 26039520Snsouch (char *)&csio->sense_data, csio->sense_len, 26139134Snsouch &vpo->vpo_sense.stat, &vpo->vpo_sense.count, 26239134Snsouch &vpo->vpo_error); 26339134Snsouch } 26439520Snsouch 26528219Smsmith 26639520Snsouch#ifdef VP0_DEBUG 26739520Snsouch printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n", 26839520Snsouch errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error); 26939520Snsouch#endif 27028257Smsmith 27139520Snsouch /* check sense return status */ 27239520Snsouch if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) { 27339520Snsouch /* sense ok */ 27439520Snsouch csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR; 27539520Snsouch csio->sense_resid = csio->sense_len - vpo->vpo_sense.count; 27628219Smsmith 27739520Snsouch#ifdef VP0_DEBUG 27839520Snsouch /* dump of sense info */ 27939520Snsouch printf("(sense) "); 28039520Snsouch for (i=0; i<vpo->vpo_sense.count; i++) 28139520Snsouch printf("%x ", ((char *)&csio->sense_data)[i]); 28239520Snsouch printf("\n"); 28339520Snsouch#endif 28439520Snsouch 28539520Snsouch } else { 28639520Snsouch /* sense failed */ 28739520Snsouch csio->ccb_h.status = CAM_AUTOSENSE_FAIL; 28839520Snsouch } 28939520Snsouch } else { 29039520Snsouch /* no sense */ 29139520Snsouch csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; 29239520Snsouch } 29339520Snsouch 29439520Snsouch goto error; 29528219Smsmith } 29628219Smsmith 29739520Snsouch csio->resid = csio->dxfer_len - vpo->vpo_count; 29839520Snsouch csio->ccb_h.status = CAM_REQ_CMP; 29928219Smsmith 30028219Smsmitherror: 30139520Snsouch splx(s); 30228219Smsmith 30328219Smsmith return; 30428219Smsmith} 30528219Smsmith 30639520Snsouchstatic void 30739520Snsouchvpo_action(struct cam_sim *sim, union ccb *ccb) 30828219Smsmith{ 30928219Smsmith 31039520Snsouch struct vpo_data *vpo = (struct vpo_data *)sim->softc; 31128219Smsmith 31239520Snsouch switch (ccb->ccb_h.func_code) { 31339520Snsouch case XPT_SCSI_IO: 31439520Snsouch { 31539520Snsouch struct ccb_scsiio *csio; 31639520Snsouch 31739520Snsouch csio = &ccb->csio; 31839520Snsouch 31939520Snsouch#ifdef VP0_DEBUG 32039520Snsouch printf("vpo%d: XPT_SCSI_IO (0x%x) request\n", 32139520Snsouch vpo->vpo_unit, csio->cdb_io.cdb_bytes[0]); 32239520Snsouch#endif 32339520Snsouch 32439520Snsouch vpo_intr(vpo, csio); 32539520Snsouch 32639520Snsouch xpt_done(ccb); 32739520Snsouch 32839520Snsouch break; 32928219Smsmith } 33039520Snsouch case XPT_CALC_GEOMETRY: 33139520Snsouch { 33239520Snsouch struct ccb_calc_geometry *ccg; 33328219Smsmith 33439520Snsouch ccg = &ccb->ccg; 33539520Snsouch 33639520Snsouch#ifdef VP0_DEBUG 33751952Sn_hibma printf("vpo%d: XPT_CALC_GEOMETRY (bs=%d,vs=%d,c=%d,h=%d,spt=%d) request\n", 33851952Sn_hibma vpo->vpo_unit, 33951952Sn_hibma ccg->block_size, 34051952Sn_hibma ccg->volume_size, 34151952Sn_hibma ccg->cylinders, 34251952Sn_hibma ccg->heads, 34351952Sn_hibma ccg->secs_per_track); 34439520Snsouch#endif 34551952Sn_hibma 34639520Snsouch ccg->heads = 64; 34739520Snsouch ccg->secs_per_track = 32; 34851952Sn_hibma ccg->cylinders = ccg->volume_size / 34951952Sn_hibma (ccg->heads * ccg->secs_per_track); 35039520Snsouch 35139520Snsouch ccb->ccb_h.status = CAM_REQ_CMP; 35239520Snsouch xpt_done(ccb); 35339520Snsouch break; 35428219Smsmith } 35539520Snsouch case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 35639520Snsouch { 35728219Smsmith 35828257Smsmith#ifdef VP0_DEBUG 35939520Snsouch printf("vpo%d: XPT_RESET_BUS request\n", vpo->vpo_unit); 36028219Smsmith#endif 36128219Smsmith 36239520Snsouch if (vpo->vpo_isplus) { 36339520Snsouch if (imm_reset_bus(&vpo->vpo_io)) { 36439520Snsouch ccb->ccb_h.status = CAM_REQ_CMP_ERR; 36539520Snsouch xpt_done(ccb); 36639520Snsouch return; 36739520Snsouch } 36839520Snsouch } else { 36939520Snsouch if (vpoio_reset_bus(&vpo->vpo_io)) { 37039520Snsouch ccb->ccb_h.status = CAM_REQ_CMP_ERR; 37139520Snsouch xpt_done(ccb); 37239520Snsouch return; 37339520Snsouch } 37439520Snsouch } 37539520Snsouch 37639520Snsouch ccb->ccb_h.status = CAM_REQ_CMP; 37739520Snsouch xpt_done(ccb); 37839520Snsouch break; 37928219Smsmith } 38039520Snsouch case XPT_PATH_INQ: /* Path routing inquiry */ 38139520Snsouch { 38239520Snsouch struct ccb_pathinq *cpi = &ccb->cpi; 38339520Snsouch 38439520Snsouch#ifdef VP0_DEBUG 38539520Snsouch printf("vpo%d: XPT_PATH_INQ request\n", vpo->vpo_unit); 38639520Snsouch#endif 38739520Snsouch cpi->version_num = 1; /* XXX??? */ 38842441Snsouch cpi->hba_inquiry = 0; 38942441Snsouch cpi->target_sprt = 0; 39042441Snsouch cpi->hba_misc = 0; 39142441Snsouch cpi->hba_eng_cnt = 0; 39239520Snsouch cpi->max_target = 7; 39339520Snsouch cpi->max_lun = 0; 39439520Snsouch cpi->initiator_id = VP0_INITIATOR; 39539520Snsouch cpi->bus_id = sim->bus_id; 39646586Sken cpi->base_transfer_speed = 93; 39739520Snsouch strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 39839520Snsouch strncpy(cpi->hba_vid, "Iomega", HBA_IDLEN); 39939520Snsouch strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 40039520Snsouch cpi->unit_number = sim->unit_number; 40128219Smsmith 40239520Snsouch cpi->ccb_h.status = CAM_REQ_CMP; 40339520Snsouch xpt_done(ccb); 40439520Snsouch break; 40539520Snsouch } 40639520Snsouch default: 40739520Snsouch ccb->ccb_h.status = CAM_REQ_INVALID; 40839520Snsouch xpt_done(ccb); 40939520Snsouch break; 41039520Snsouch } 41128219Smsmith 41239520Snsouch return; 41339520Snsouch} 41428219Smsmith 41539520Snsouchstatic void 41639520Snsouchvpo_poll(struct cam_sim *sim) 41739520Snsouch{ 41839520Snsouch /* The ZIP is actually always polled throw vpo_action() */ 41939520Snsouch return; 42028219Smsmith} 42155939Snsouch 42256455Speterstatic devclass_t vpo_devclass; 42356455Speter 42456455Speterstatic device_method_t vpo_methods[] = { 42556455Speter /* device interface */ 42656455Speter DEVMETHOD(device_identify, vpo_identify), 42756455Speter DEVMETHOD(device_probe, vpo_probe), 42856455Speter DEVMETHOD(device_attach, vpo_attach), 42956455Speter 43056455Speter { 0, 0 } 43156455Speter}; 43256455Speter 43356455Speterstatic driver_t vpo_driver = { 43456455Speter "vpo", 43556455Speter vpo_methods, 43656455Speter sizeof(struct vpo_data), 43756455Speter}; 43855939SnsouchDRIVER_MODULE(vpo, ppbus, vpo_driver, vpo_devclass, 0, 0); 439