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