1*57718be8SEnji Cooper /* $NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $ */ 2*57718be8SEnji Cooper 3*57718be8SEnji Cooper /* 4*57718be8SEnji Cooper * Copyright (c) 2010 Antti Kantee. All Rights Reserved. 5*57718be8SEnji Cooper * 6*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without 7*57718be8SEnji Cooper * modification, are permitted provided that the following conditions 8*57718be8SEnji Cooper * are met: 9*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright 10*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer. 11*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 12*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the 13*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution. 14*57718be8SEnji Cooper * 15*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16*57718be8SEnji Cooper * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17*57718be8SEnji Cooper * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18*57718be8SEnji Cooper * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*57718be8SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*57718be8SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21*57718be8SEnji Cooper * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*57718be8SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*57718be8SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*57718be8SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*57718be8SEnji Cooper * SUCH DAMAGE. 26*57718be8SEnji Cooper */ 27*57718be8SEnji Cooper 28*57718be8SEnji Cooper /* 29*57718be8SEnji Cooper * A SCSI target which is useful for debugging our scsipi driver stack. 30*57718be8SEnji Cooper * Currently it pretends to be a single CD. 31*57718be8SEnji Cooper * 32*57718be8SEnji Cooper * Freely add the necessary features for your tests. Just remember to 33*57718be8SEnji Cooper * run the atf test suite to make sure you didn't cause regressions to 34*57718be8SEnji Cooper * other tests. 35*57718be8SEnji Cooper */ 36*57718be8SEnji Cooper 37*57718be8SEnji Cooper #include <sys/cdefs.h> 38*57718be8SEnji Cooper __KERNEL_RCSID(0, "$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $"); 39*57718be8SEnji Cooper 40*57718be8SEnji Cooper #include <sys/param.h> 41*57718be8SEnji Cooper #include <sys/atomic.h> 42*57718be8SEnji Cooper #include <sys/buf.h> 43*57718be8SEnji Cooper #include <sys/device.h> 44*57718be8SEnji Cooper #include <sys/malloc.h> 45*57718be8SEnji Cooper #include <sys/fcntl.h> 46*57718be8SEnji Cooper 47*57718be8SEnji Cooper #include <dev/scsipi/scsiconf.h> 48*57718be8SEnji Cooper #include <dev/scsipi/scsipiconf.h> 49*57718be8SEnji Cooper #include <dev/scsipi/scsi_disk.h> 50*57718be8SEnji Cooper #include <dev/scsipi/scsipi_cd.h> 51*57718be8SEnji Cooper #include <dev/scsipi/scsipi_all.h> 52*57718be8SEnji Cooper 53*57718be8SEnji Cooper #include <rump/rumpuser.h> 54*57718be8SEnji Cooper 55*57718be8SEnji Cooper #include "scsitest.h" 56*57718be8SEnji Cooper 57*57718be8SEnji Cooper int scsitest_match(device_t, cfdata_t, void *); 58*57718be8SEnji Cooper void scsitest_attach(device_t, device_t, void *); 59*57718be8SEnji Cooper 60*57718be8SEnji Cooper struct scsitest { 61*57718be8SEnji Cooper struct scsipi_channel sc_channel; 62*57718be8SEnji Cooper struct scsipi_adapter sc_adapter; 63*57718be8SEnji Cooper }; 64*57718be8SEnji Cooper 65*57718be8SEnji Cooper CFATTACH_DECL_NEW(scsitest, sizeof(struct scsitest), scsitest_match, 66*57718be8SEnji Cooper scsitest_attach, NULL, NULL); 67*57718be8SEnji Cooper 68*57718be8SEnji Cooper /* 69*57718be8SEnji Cooper * tosi.iso can be used to deliver CD requests to a host file with the 70*57718be8SEnji Cooper * name in USE_TOSI_ISO (yes, it's extrasimplistic). 71*57718be8SEnji Cooper */ 72*57718be8SEnji Cooper //#define USE_TOSI_ISO 73*57718be8SEnji Cooper 74*57718be8SEnji Cooper #define CDBLOCKSIZE 2048 75*57718be8SEnji Cooper static uint32_t mycdsize = 2048; 76*57718be8SEnji Cooper static int isofd; 77*57718be8SEnji Cooper 78*57718be8SEnji Cooper #define MYCDISO "tosi.iso" 79*57718be8SEnji Cooper 80*57718be8SEnji Cooper unsigned rump_scsitest_err[RUMP_SCSITEST_MAXERROR]; 81*57718be8SEnji Cooper 82*57718be8SEnji Cooper static void 83*57718be8SEnji Cooper sense_notready(struct scsipi_xfer *xs) 84*57718be8SEnji Cooper { 85*57718be8SEnji Cooper struct scsi_sense_data *sense = &xs->sense.scsi_sense; 86*57718be8SEnji Cooper 87*57718be8SEnji Cooper xs->error = XS_SENSE; 88*57718be8SEnji Cooper 89*57718be8SEnji Cooper sense->response_code = 0x70; 90*57718be8SEnji Cooper sense->flags = SKEY_NOT_READY; 91*57718be8SEnji Cooper sense->asc = 0x3A; 92*57718be8SEnji Cooper sense->ascq = 0x00; 93*57718be8SEnji Cooper sense->extra_len = 6; 94*57718be8SEnji Cooper } 95*57718be8SEnji Cooper 96*57718be8SEnji Cooper /* 97*57718be8SEnji Cooper * This is pretty much a CD target for now 98*57718be8SEnji Cooper */ 99*57718be8SEnji Cooper static void 100*57718be8SEnji Cooper scsitest_request(struct scsipi_channel *chan, 101*57718be8SEnji Cooper scsipi_adapter_req_t req, void *arg) 102*57718be8SEnji Cooper { 103*57718be8SEnji Cooper struct scsipi_xfer *xs = arg; 104*57718be8SEnji Cooper struct scsipi_generic *cmd = xs->cmd; 105*57718be8SEnji Cooper #ifdef USE_TOSI_ISO 106*57718be8SEnji Cooper int error; 107*57718be8SEnji Cooper #endif 108*57718be8SEnji Cooper 109*57718be8SEnji Cooper if (req != ADAPTER_REQ_RUN_XFER) 110*57718be8SEnji Cooper return; 111*57718be8SEnji Cooper 112*57718be8SEnji Cooper //show_scsipi_xs(xs); 113*57718be8SEnji Cooper 114*57718be8SEnji Cooper switch (cmd->opcode) { 115*57718be8SEnji Cooper case SCSI_TEST_UNIT_READY: 116*57718be8SEnji Cooper if (isofd == -1) 117*57718be8SEnji Cooper sense_notready(xs); 118*57718be8SEnji Cooper 119*57718be8SEnji Cooper break; 120*57718be8SEnji Cooper case INQUIRY: { 121*57718be8SEnji Cooper struct scsipi_inquiry_data *inqbuf = (void *)xs->data; 122*57718be8SEnji Cooper 123*57718be8SEnji Cooper memset(inqbuf, 0, sizeof(*inqbuf)); 124*57718be8SEnji Cooper inqbuf->device = T_CDROM; 125*57718be8SEnji Cooper inqbuf->dev_qual2 = SID_REMOVABLE; 126*57718be8SEnji Cooper strcpy(inqbuf->vendor, "RUMPHOBO"); 127*57718be8SEnji Cooper strcpy(inqbuf->product, "It's a LIE"); 128*57718be8SEnji Cooper strcpy(inqbuf->revision, "0.00"); 129*57718be8SEnji Cooper break; 130*57718be8SEnji Cooper } 131*57718be8SEnji Cooper case READ_CD_CAPACITY: { 132*57718be8SEnji Cooper struct scsipi_read_cd_cap_data *ret = (void *)xs->data; 133*57718be8SEnji Cooper 134*57718be8SEnji Cooper _lto4b(CDBLOCKSIZE, ret->length); 135*57718be8SEnji Cooper _lto4b(mycdsize, ret->addr); 136*57718be8SEnji Cooper 137*57718be8SEnji Cooper break; 138*57718be8SEnji Cooper } 139*57718be8SEnji Cooper case READ_DISCINFO: { 140*57718be8SEnji Cooper struct scsipi_read_discinfo_data *ret = (void *)xs->data; 141*57718be8SEnji Cooper 142*57718be8SEnji Cooper memset(ret, 0, sizeof(*ret)); 143*57718be8SEnji Cooper break; 144*57718be8SEnji Cooper } 145*57718be8SEnji Cooper case READ_TRACKINFO: { 146*57718be8SEnji Cooper struct scsipi_read_trackinfo_data *ret = (void *)xs->data; 147*57718be8SEnji Cooper 148*57718be8SEnji Cooper _lto4b(mycdsize, ret->track_size); 149*57718be8SEnji Cooper break; 150*57718be8SEnji Cooper } 151*57718be8SEnji Cooper case READ_TOC: { 152*57718be8SEnji Cooper struct scsipi_toc_header *ret = (void *)xs->data; 153*57718be8SEnji Cooper 154*57718be8SEnji Cooper memset(ret, 0, sizeof(*ret)); 155*57718be8SEnji Cooper break; 156*57718be8SEnji Cooper } 157*57718be8SEnji Cooper case START_STOP: { 158*57718be8SEnji Cooper struct scsipi_start_stop *param = (void *)cmd; 159*57718be8SEnji Cooper 160*57718be8SEnji Cooper if (param->how & SSS_LOEJ) { 161*57718be8SEnji Cooper #ifdef USE_TOSI_ISO 162*57718be8SEnji Cooper rumpuser_close(isofd, &error); 163*57718be8SEnji Cooper #endif 164*57718be8SEnji Cooper isofd = -1; 165*57718be8SEnji Cooper } 166*57718be8SEnji Cooper break; 167*57718be8SEnji Cooper } 168*57718be8SEnji Cooper case SCSI_SYNCHRONIZE_CACHE_10: { 169*57718be8SEnji Cooper if (isofd == -1) { 170*57718be8SEnji Cooper if ((xs->xs_control & XS_CTL_SILENT) == 0) 171*57718be8SEnji Cooper atomic_inc_uint(&rump_scsitest_err 172*57718be8SEnji Cooper [RUMP_SCSITEST_NOISYSYNC]); 173*57718be8SEnji Cooper 174*57718be8SEnji Cooper sense_notready(xs); 175*57718be8SEnji Cooper } 176*57718be8SEnji Cooper 177*57718be8SEnji Cooper break; 178*57718be8SEnji Cooper } 179*57718be8SEnji Cooper case GET_CONFIGURATION: { 180*57718be8SEnji Cooper memset(xs->data, 0, sizeof(struct scsipi_get_conf_data)); 181*57718be8SEnji Cooper break; 182*57718be8SEnji Cooper } 183*57718be8SEnji Cooper case SCSI_READ_6_COMMAND: { 184*57718be8SEnji Cooper #ifdef USE_TOSI_ISO 185*57718be8SEnji Cooper struct scsi_rw_6 *param = (void *)cmd; 186*57718be8SEnji Cooper 187*57718be8SEnji Cooper printf("reading %d bytes from %d\n", 188*57718be8SEnji Cooper param->length * CDBLOCKSIZE, 189*57718be8SEnji Cooper _3btol(param->addr) * CDBLOCKSIZE); 190*57718be8SEnji Cooper rumpuser_pread(isofd, xs->data, 191*57718be8SEnji Cooper param->length * CDBLOCKSIZE, 192*57718be8SEnji Cooper _3btol(param->addr) * CDBLOCKSIZE, 193*57718be8SEnji Cooper &error); 194*57718be8SEnji Cooper #endif 195*57718be8SEnji Cooper 196*57718be8SEnji Cooper break; 197*57718be8SEnji Cooper } 198*57718be8SEnji Cooper case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: 199*57718be8SEnji Cooper /* hardcoded for now */ 200*57718be8SEnji Cooper break; 201*57718be8SEnji Cooper default: 202*57718be8SEnji Cooper printf("unhandled opcode 0x%x\n", cmd->opcode); 203*57718be8SEnji Cooper break; 204*57718be8SEnji Cooper } 205*57718be8SEnji Cooper 206*57718be8SEnji Cooper scsipi_done(xs); 207*57718be8SEnji Cooper } 208*57718be8SEnji Cooper 209*57718be8SEnji Cooper int 210*57718be8SEnji Cooper scsitest_match(device_t parent, cfdata_t match, void *aux) 211*57718be8SEnji Cooper { 212*57718be8SEnji Cooper #ifdef USE_TOSI_ISO 213*57718be8SEnji Cooper uint64_t fsize; 214*57718be8SEnji Cooper int error, ft; 215*57718be8SEnji Cooper 216*57718be8SEnji Cooper if (rumpuser_getfileinfo(MYCDISO, &fsize, &ft, &error)) 217*57718be8SEnji Cooper return 0; 218*57718be8SEnji Cooper if (ft != RUMPUSER_FT_REG) 219*57718be8SEnji Cooper return 0; 220*57718be8SEnji Cooper mycdsize = fsize / CDBLOCKSIZE; 221*57718be8SEnji Cooper 222*57718be8SEnji Cooper if ((isofd = rumpuser_open(MYCDISO, RUMPUSER_OPEN_RDWR, &error)) == -1) 223*57718be8SEnji Cooper return 0; 224*57718be8SEnji Cooper #else 225*57718be8SEnji Cooper /* 226*57718be8SEnji Cooper * We pretend to have a medium present initially, so != -1. 227*57718be8SEnji Cooper */ 228*57718be8SEnji Cooper isofd = -2; 229*57718be8SEnji Cooper #endif 230*57718be8SEnji Cooper 231*57718be8SEnji Cooper return 1; 232*57718be8SEnji Cooper } 233*57718be8SEnji Cooper 234*57718be8SEnji Cooper void 235*57718be8SEnji Cooper scsitest_attach(device_t parent, device_t self, void *aux) 236*57718be8SEnji Cooper { 237*57718be8SEnji Cooper struct scsitest *sc = device_private(self); 238*57718be8SEnji Cooper 239*57718be8SEnji Cooper aprint_naive("\n"); 240*57718be8SEnji Cooper aprint_normal("\n"); 241*57718be8SEnji Cooper 242*57718be8SEnji Cooper memset(&sc->sc_adapter, 0, sizeof(sc->sc_adapter)); 243*57718be8SEnji Cooper sc->sc_adapter.adapt_nchannels = 1; 244*57718be8SEnji Cooper sc->sc_adapter.adapt_request = scsitest_request; 245*57718be8SEnji Cooper sc->sc_adapter.adapt_minphys = minphys; 246*57718be8SEnji Cooper sc->sc_adapter.adapt_dev = self; 247*57718be8SEnji Cooper sc->sc_adapter.adapt_max_periph = 1; 248*57718be8SEnji Cooper sc->sc_adapter.adapt_openings = 1; 249*57718be8SEnji Cooper 250*57718be8SEnji Cooper memset(&sc->sc_channel, 0, sizeof(sc->sc_channel)); 251*57718be8SEnji Cooper sc->sc_channel.chan_bustype = &scsi_bustype; 252*57718be8SEnji Cooper sc->sc_channel.chan_ntargets = 2; 253*57718be8SEnji Cooper sc->sc_channel.chan_nluns = 1; 254*57718be8SEnji Cooper sc->sc_channel.chan_id = 0; 255*57718be8SEnji Cooper sc->sc_channel.chan_flags = SCSIPI_CHAN_NOSETTLE; 256*57718be8SEnji Cooper sc->sc_channel.chan_adapter = &sc->sc_adapter; 257*57718be8SEnji Cooper 258*57718be8SEnji Cooper config_found_ia(self, "scsi", &sc->sc_channel, scsiprint); 259*57718be8SEnji Cooper } 260