1272343Sngie/* $NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $ */ 2272343Sngie 3272343Sngie/* 4272343Sngie * Copyright (c) 2010 Antti Kantee. All Rights Reserved. 5272343Sngie * 6272343Sngie * Redistribution and use in source and binary forms, with or without 7272343Sngie * modification, are permitted provided that the following conditions 8272343Sngie * are met: 9272343Sngie * 1. Redistributions of source code must retain the above copyright 10272343Sngie * notice, this list of conditions and the following disclaimer. 11272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie * notice, this list of conditions and the following disclaimer in the 13272343Sngie * documentation and/or other materials provided with the distribution. 14272343Sngie * 15272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16272343Sngie * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17272343Sngie * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18272343Sngie * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21272343Sngie * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25272343Sngie * SUCH DAMAGE. 26272343Sngie */ 27272343Sngie 28272343Sngie/* 29272343Sngie * A SCSI target which is useful for debugging our scsipi driver stack. 30272343Sngie * Currently it pretends to be a single CD. 31272343Sngie * 32272343Sngie * Freely add the necessary features for your tests. Just remember to 33272343Sngie * run the atf test suite to make sure you didn't cause regressions to 34272343Sngie * other tests. 35272343Sngie */ 36272343Sngie 37272343Sngie#include <sys/cdefs.h> 38272343Sngie__KERNEL_RCSID(0, "$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $"); 39272343Sngie 40272343Sngie#include <sys/param.h> 41272343Sngie#include <sys/atomic.h> 42272343Sngie#include <sys/buf.h> 43272343Sngie#include <sys/device.h> 44272343Sngie#include <sys/malloc.h> 45272343Sngie#include <sys/fcntl.h> 46272343Sngie 47272343Sngie#include <dev/scsipi/scsiconf.h> 48272343Sngie#include <dev/scsipi/scsipiconf.h> 49272343Sngie#include <dev/scsipi/scsi_disk.h> 50272343Sngie#include <dev/scsipi/scsipi_cd.h> 51272343Sngie#include <dev/scsipi/scsipi_all.h> 52272343Sngie 53272343Sngie#include <rump/rumpuser.h> 54272343Sngie 55272343Sngie#include "scsitest.h" 56272343Sngie 57272343Sngieint scsitest_match(device_t, cfdata_t, void *); 58272343Sngievoid scsitest_attach(device_t, device_t, void *); 59272343Sngie 60272343Sngiestruct scsitest { 61272343Sngie struct scsipi_channel sc_channel; 62272343Sngie struct scsipi_adapter sc_adapter; 63272343Sngie}; 64272343Sngie 65272343SngieCFATTACH_DECL_NEW(scsitest, sizeof(struct scsitest), scsitest_match, 66272343Sngie scsitest_attach, NULL, NULL); 67272343Sngie 68272343Sngie/* 69272343Sngie * tosi.iso can be used to deliver CD requests to a host file with the 70272343Sngie * name in USE_TOSI_ISO (yes, it's extrasimplistic). 71272343Sngie */ 72272343Sngie//#define USE_TOSI_ISO 73272343Sngie 74272343Sngie#define CDBLOCKSIZE 2048 75272343Sngiestatic uint32_t mycdsize = 2048; 76272343Sngiestatic int isofd; 77272343Sngie 78272343Sngie#define MYCDISO "tosi.iso" 79272343Sngie 80272343Sngieunsigned rump_scsitest_err[RUMP_SCSITEST_MAXERROR]; 81272343Sngie 82272343Sngiestatic void 83272343Sngiesense_notready(struct scsipi_xfer *xs) 84272343Sngie{ 85272343Sngie struct scsi_sense_data *sense = &xs->sense.scsi_sense; 86272343Sngie 87272343Sngie xs->error = XS_SENSE; 88272343Sngie 89272343Sngie sense->response_code = 0x70; 90272343Sngie sense->flags = SKEY_NOT_READY; 91272343Sngie sense->asc = 0x3A; 92272343Sngie sense->ascq = 0x00; 93272343Sngie sense->extra_len = 6; 94272343Sngie} 95272343Sngie 96272343Sngie/* 97272343Sngie * This is pretty much a CD target for now 98272343Sngie */ 99272343Sngiestatic void 100272343Sngiescsitest_request(struct scsipi_channel *chan, 101272343Sngie scsipi_adapter_req_t req, void *arg) 102272343Sngie{ 103272343Sngie struct scsipi_xfer *xs = arg; 104272343Sngie struct scsipi_generic *cmd = xs->cmd; 105272343Sngie#ifdef USE_TOSI_ISO 106272343Sngie int error; 107272343Sngie#endif 108272343Sngie 109272343Sngie if (req != ADAPTER_REQ_RUN_XFER) 110272343Sngie return; 111272343Sngie 112272343Sngie //show_scsipi_xs(xs); 113272343Sngie 114272343Sngie switch (cmd->opcode) { 115272343Sngie case SCSI_TEST_UNIT_READY: 116272343Sngie if (isofd == -1) 117272343Sngie sense_notready(xs); 118272343Sngie 119272343Sngie break; 120272343Sngie case INQUIRY: { 121272343Sngie struct scsipi_inquiry_data *inqbuf = (void *)xs->data; 122272343Sngie 123272343Sngie memset(inqbuf, 0, sizeof(*inqbuf)); 124272343Sngie inqbuf->device = T_CDROM; 125272343Sngie inqbuf->dev_qual2 = SID_REMOVABLE; 126272343Sngie strcpy(inqbuf->vendor, "RUMPHOBO"); 127272343Sngie strcpy(inqbuf->product, "It's a LIE"); 128272343Sngie strcpy(inqbuf->revision, "0.00"); 129272343Sngie break; 130272343Sngie } 131272343Sngie case READ_CD_CAPACITY: { 132272343Sngie struct scsipi_read_cd_cap_data *ret = (void *)xs->data; 133272343Sngie 134272343Sngie _lto4b(CDBLOCKSIZE, ret->length); 135272343Sngie _lto4b(mycdsize, ret->addr); 136272343Sngie 137272343Sngie break; 138272343Sngie } 139272343Sngie case READ_DISCINFO: { 140272343Sngie struct scsipi_read_discinfo_data *ret = (void *)xs->data; 141272343Sngie 142272343Sngie memset(ret, 0, sizeof(*ret)); 143272343Sngie break; 144272343Sngie } 145272343Sngie case READ_TRACKINFO: { 146272343Sngie struct scsipi_read_trackinfo_data *ret = (void *)xs->data; 147272343Sngie 148272343Sngie _lto4b(mycdsize, ret->track_size); 149272343Sngie break; 150272343Sngie } 151272343Sngie case READ_TOC: { 152272343Sngie struct scsipi_toc_header *ret = (void *)xs->data; 153272343Sngie 154272343Sngie memset(ret, 0, sizeof(*ret)); 155272343Sngie break; 156272343Sngie } 157272343Sngie case START_STOP: { 158272343Sngie struct scsipi_start_stop *param = (void *)cmd; 159272343Sngie 160272343Sngie if (param->how & SSS_LOEJ) { 161272343Sngie#ifdef USE_TOSI_ISO 162272343Sngie rumpuser_close(isofd, &error); 163272343Sngie#endif 164272343Sngie isofd = -1; 165272343Sngie } 166272343Sngie break; 167272343Sngie } 168272343Sngie case SCSI_SYNCHRONIZE_CACHE_10: { 169272343Sngie if (isofd == -1) { 170272343Sngie if ((xs->xs_control & XS_CTL_SILENT) == 0) 171272343Sngie atomic_inc_uint(&rump_scsitest_err 172272343Sngie [RUMP_SCSITEST_NOISYSYNC]); 173272343Sngie 174272343Sngie sense_notready(xs); 175272343Sngie } 176272343Sngie 177272343Sngie break; 178272343Sngie } 179272343Sngie case GET_CONFIGURATION: { 180272343Sngie memset(xs->data, 0, sizeof(struct scsipi_get_conf_data)); 181272343Sngie break; 182272343Sngie } 183272343Sngie case SCSI_READ_6_COMMAND: { 184272343Sngie#ifdef USE_TOSI_ISO 185272343Sngie struct scsi_rw_6 *param = (void *)cmd; 186272343Sngie 187272343Sngie printf("reading %d bytes from %d\n", 188272343Sngie param->length * CDBLOCKSIZE, 189272343Sngie _3btol(param->addr) * CDBLOCKSIZE); 190272343Sngie rumpuser_pread(isofd, xs->data, 191272343Sngie param->length * CDBLOCKSIZE, 192272343Sngie _3btol(param->addr) * CDBLOCKSIZE, 193272343Sngie &error); 194272343Sngie#endif 195272343Sngie 196272343Sngie break; 197272343Sngie } 198272343Sngie case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: 199272343Sngie /* hardcoded for now */ 200272343Sngie break; 201272343Sngie default: 202272343Sngie printf("unhandled opcode 0x%x\n", cmd->opcode); 203272343Sngie break; 204272343Sngie } 205272343Sngie 206272343Sngie scsipi_done(xs); 207272343Sngie} 208272343Sngie 209272343Sngieint 210272343Sngiescsitest_match(device_t parent, cfdata_t match, void *aux) 211272343Sngie{ 212272343Sngie#ifdef USE_TOSI_ISO 213272343Sngie uint64_t fsize; 214272343Sngie int error, ft; 215272343Sngie 216272343Sngie if (rumpuser_getfileinfo(MYCDISO, &fsize, &ft, &error)) 217272343Sngie return 0; 218272343Sngie if (ft != RUMPUSER_FT_REG) 219272343Sngie return 0; 220272343Sngie mycdsize = fsize / CDBLOCKSIZE; 221272343Sngie 222272343Sngie if ((isofd = rumpuser_open(MYCDISO, RUMPUSER_OPEN_RDWR, &error)) == -1) 223272343Sngie return 0; 224272343Sngie#else 225272343Sngie /* 226272343Sngie * We pretend to have a medium present initially, so != -1. 227272343Sngie */ 228272343Sngie isofd = -2; 229272343Sngie#endif 230272343Sngie 231272343Sngie return 1; 232272343Sngie} 233272343Sngie 234272343Sngievoid 235272343Sngiescsitest_attach(device_t parent, device_t self, void *aux) 236272343Sngie{ 237272343Sngie struct scsitest *sc = device_private(self); 238272343Sngie 239272343Sngie aprint_naive("\n"); 240272343Sngie aprint_normal("\n"); 241272343Sngie 242272343Sngie memset(&sc->sc_adapter, 0, sizeof(sc->sc_adapter)); 243272343Sngie sc->sc_adapter.adapt_nchannels = 1; 244272343Sngie sc->sc_adapter.adapt_request = scsitest_request; 245272343Sngie sc->sc_adapter.adapt_minphys = minphys; 246272343Sngie sc->sc_adapter.adapt_dev = self; 247272343Sngie sc->sc_adapter.adapt_max_periph = 1; 248272343Sngie sc->sc_adapter.adapt_openings = 1; 249272343Sngie 250272343Sngie memset(&sc->sc_channel, 0, sizeof(sc->sc_channel)); 251272343Sngie sc->sc_channel.chan_bustype = &scsi_bustype; 252272343Sngie sc->sc_channel.chan_ntargets = 2; 253272343Sngie sc->sc_channel.chan_nluns = 1; 254272343Sngie sc->sc_channel.chan_id = 0; 255272343Sngie sc->sc_channel.chan_flags = SCSIPI_CHAN_NOSETTLE; 256272343Sngie sc->sc_channel.chan_adapter = &sc->sc_adapter; 257272343Sngie 258272343Sngie config_found_ia(self, "scsi", &sc->sc_channel, scsiprint); 259272343Sngie} 260