1211088Smjacob/*-
2211088Smjacob * Copyright (c) 2010 by Panasas, Inc.
3211088Smjacob * All rights reserved.
4211088Smjacob *
5211088Smjacob * Redistribution and use in source and binary forms, with or without
6211088Smjacob * modification, are permitted provided that the following conditions
7211088Smjacob * are met:
8211088Smjacob * 1. Redistributions of source code must retain the above copyright
9211088Smjacob *    notice immediately at the beginning of the file, without modification,
10211088Smjacob *    this list of conditions, and the following disclaimer.
11211088Smjacob * 2. The name of the author may not be used to endorse or promote products
12211088Smjacob *    derived from this software without specific prior written permission.
13211088Smjacob *
14211088Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15211088Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16211088Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17211088Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18211088Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19211088Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20211088Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21211088Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22211088Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23211088Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24211088Smjacob * SUCH DAMAGE.
25211088Smjacob */
26211088Smjacob/* $FreeBSD$ */
27211088Smjacob/*
28211088Smjacob * "Faulty" Multipath Device. Creates to devices to be set up as multipath,
29211088Smjacob * makes one or both of them non existent (or re existent) on demand.
30211088Smjacob */
31211088Smjacob#include "vhba.h"
32211088Smjacob#include <sys/sysctl.h>
33211088Smjacob
34211183Smjacobstatic int vhba_stop_lun;
35211183Smjacobstatic int vhba_start_lun = 0;
36211183Smjacobstatic int vhba_notify_stop = 1;
37211183Smjacobstatic int vhba_notify_start = 1;
38211183Smjacobstatic int vhba_inject_hwerr = 0;
39211183SmjacobSYSCTL_INT(_debug, OID_AUTO, vhba_stop_lun, CTLFLAG_RW, &vhba_stop_lun, 0, "stop lun bitmap");
40211183SmjacobSYSCTL_INT(_debug, OID_AUTO, vhba_start_lun, CTLFLAG_RW, &vhba_start_lun, 0, "start lun bitmap");
41211183SmjacobSYSCTL_INT(_debug, OID_AUTO, vhba_notify_stop, CTLFLAG_RW, &vhba_notify_stop, 1, "notify when luns go away");
42211183SmjacobSYSCTL_INT(_debug, OID_AUTO, vhba_notify_start, CTLFLAG_RW, &vhba_notify_start, 1, "notify when luns arrive");
43211183SmjacobSYSCTL_INT(_debug, OID_AUTO, vhba_inject_hwerr, CTLFLAG_RW, &vhba_inject_hwerr, 0, "inject hardware error on lost luns");
44211183Smjacob
45211088Smjacob#define	MAX_TGT		1
46211088Smjacob#define	MAX_LUN		2
47211088Smjacob#define	VMP_TIME	hz
48211088Smjacob
49211088Smjacob#define	DISK_SIZE	32
50211088Smjacob#define	DISK_SHIFT	9
51211088Smjacob#define	DISK_NBLKS	((DISK_SIZE << 20) >> DISK_SHIFT)
52211088Smjacob#define	PSEUDO_SPT	64
53211088Smjacob#define	PSEUDO_HDS	64
54211088Smjacob#define	PSEUDO_SPC	(PSEUDO_SPT * PSEUDO_HDS)
55211088Smjacob
56211088Smjacobtypedef struct {
57211088Smjacob	vhba_softc_t *	vhba;
58211088Smjacob	uint8_t *	disk;
59211088Smjacob	size_t		disk_size;
60211088Smjacob	int		luns[2];
61211088Smjacob	struct callout	tick;
62211088Smjacob	struct task	qt;
63211183Smjacob	TAILQ_HEAD(, ccb_hdr)   inproc;
64211183Smjacob	int		nact, nact_high;
65211088Smjacob} mptest_t;
66211088Smjacob
67211183Smjacobstatic timeout_t vhba_iodelay;
68211088Smjacobstatic timeout_t vhba_timer;
69211088Smjacobstatic void vhba_task(void *, int);
70211088Smjacobstatic void mptest_act(mptest_t *, struct ccb_scsiio *);
71211088Smjacob
72211088Smjacobvoid
73211088Smjacobvhba_init(vhba_softc_t *vhba)
74211088Smjacob{
75211088Smjacob	static mptest_t vhbastatic;
76211183Smjacob
77211088Smjacob	vhbastatic.vhba = vhba;
78211088Smjacob	vhbastatic.disk_size = DISK_SIZE << 20;
79211088Smjacob	vhbastatic.disk = malloc(vhbastatic.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
80211088Smjacob	vhba->private = &vhbastatic;
81211088Smjacob	callout_init_mtx(&vhbastatic.tick, &vhba->lock, 0);
82211088Smjacob	callout_reset(&vhbastatic.tick, VMP_TIME, vhba_timer, vhba);
83211183Smjacob	TAILQ_INIT(&vhbastatic.inproc);
84211088Smjacob	TASK_INIT(&vhbastatic.qt, 0, vhba_task, &vhbastatic);
85211183Smjacob	vhbastatic.luns[0] = 1;
86211183Smjacob	vhbastatic.luns[1] = 1;
87211088Smjacob}
88211088Smjacob
89211088Smjacobvoid
90211088Smjacobvhba_fini(vhba_softc_t *vhba)
91211088Smjacob{
92211088Smjacob	mptest_t *vhbas = vhba->private;
93211088Smjacob	callout_stop(&vhbas->tick);
94211088Smjacob	vhba->private = NULL;
95211088Smjacob	free(vhbas->disk, M_DEVBUF);
96211088Smjacob}
97211088Smjacob
98211088Smjacobvoid
99211088Smjacobvhba_kick(vhba_softc_t *vhba)
100211088Smjacob{
101211088Smjacob	mptest_t *vhbas = vhba->private;
102211088Smjacob	taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
103211088Smjacob}
104211088Smjacob
105211088Smjacobstatic void
106211088Smjacobvhba_task(void *arg, int pending)
107211088Smjacob{
108211088Smjacob	mptest_t *vhbas = arg;
109211088Smjacob	struct ccb_hdr *ccbh;
110211183Smjacob	int nadded = 0;
111211088Smjacob
112211088Smjacob	mtx_lock(&vhbas->vhba->lock);
113211088Smjacob	while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
114211088Smjacob		TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
115211088Smjacob                mptest_act(vhbas, (struct ccb_scsiio *)ccbh);
116211183Smjacob		nadded++;
117211183Smjacob		ccbh->sim_priv.entries[0].ptr = vhbas;
118211183Smjacob		callout_handle_init(&ccbh->timeout_ch);
119211088Smjacob	}
120211183Smjacob	if (nadded) {
121211183Smjacob		vhba_kick(vhbas->vhba);
122211183Smjacob	} else {
123211183Smjacob		while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
124211183Smjacob			TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
125211183Smjacob			xpt_done((union ccb *)ccbh);
126211183Smjacob		}
127211088Smjacob	}
128211088Smjacob	mtx_unlock(&vhbas->vhba->lock);
129211088Smjacob}
130211088Smjacob
131211088Smjacobstatic void
132211088Smjacobmptest_act(mptest_t *vhbas, struct ccb_scsiio *csio)
133211088Smjacob{
134211088Smjacob	char junk[128];
135211088Smjacob	cam_status camstatus;
136211088Smjacob	uint8_t *cdb, *ptr, status;
137211183Smjacob	uint32_t data_len, blkcmd;
138211088Smjacob	uint64_t off;
139211088Smjacob
140211183Smjacob	blkcmd = data_len = 0;
141211088Smjacob	status = SCSI_STATUS_OK;
142211088Smjacob
143211088Smjacob	memset(&csio->sense_data, 0, sizeof (csio->sense_data));
144211088Smjacob	cdb = csio->cdb_io.cdb_bytes;
145211088Smjacob
146211088Smjacob	if (csio->ccb_h.target_id >= MAX_TGT) {
147211088Smjacob		vhba_set_status(&csio->ccb_h, CAM_SEL_TIMEOUT);
148211088Smjacob		TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
149211088Smjacob		return;
150211088Smjacob	}
151211183Smjacob	if (vhba_inject_hwerr && csio->ccb_h.target_lun < MAX_LUN && vhbas->luns[csio->ccb_h.target_lun] == 0) {
152211183Smjacob		vhba_fill_sense(csio, SSD_KEY_HARDWARE_ERROR, 0x44, 0x0);
153211183Smjacob		TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
154211183Smjacob		return;
155211183Smjacob	}
156211088Smjacob	if ((csio->ccb_h.target_lun >= MAX_LUN || vhbas->luns[csio->ccb_h.target_lun] == 0) && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
157211088Smjacob		vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
158211088Smjacob		TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
159211088Smjacob		return;
160211088Smjacob	}
161211088Smjacob
162211088Smjacob	switch (cdb[0]) {
163211088Smjacob	case MODE_SENSE:
164211088Smjacob	case MODE_SENSE_10:
165211088Smjacob	{
166211088Smjacob		unsigned int nbyte;
167211088Smjacob		uint8_t page = cdb[2] & SMS_PAGE_CODE;
168211088Smjacob		uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
169211088Smjacob
170211088Smjacob		switch (page) {
171211088Smjacob		case SMS_FORMAT_DEVICE_PAGE:
172211088Smjacob		case SMS_GEOMETRY_PAGE:
173211088Smjacob		case SMS_CACHE_PAGE:
174211088Smjacob		case SMS_CONTROL_MODE_PAGE:
175211088Smjacob		case SMS_ALL_PAGES_PAGE:
176211088Smjacob			break;
177211088Smjacob		default:
178211088Smjacob			vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
179211088Smjacob			TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
180211088Smjacob			return;
181211088Smjacob		}
182211088Smjacob		memset(junk, 0, sizeof (junk));
183211088Smjacob		if (cdb[1] & SMS_DBD) {
184211088Smjacob			ptr = &junk[4];
185211088Smjacob		} else {
186211088Smjacob			ptr = junk;
187211088Smjacob			ptr[3] = 8;
188211088Smjacob			ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
189211088Smjacob			ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
190211088Smjacob			ptr[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
191211088Smjacob			ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
192211088Smjacob
193211088Smjacob			ptr[8] = (DISK_NBLKS >> 24) & 0xff;
194211088Smjacob			ptr[9] = (DISK_NBLKS >> 16) & 0xff;
195211088Smjacob			ptr[10] = (DISK_NBLKS >> 8) & 0xff;
196211088Smjacob			ptr[11] = DISK_NBLKS & 0xff;
197211088Smjacob			ptr += 12;
198211088Smjacob		}
199211088Smjacob
200211088Smjacob		if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
201211088Smjacob			ptr[0] = SMS_FORMAT_DEVICE_PAGE;
202211088Smjacob			ptr[1] = 24;
203211088Smjacob			if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
204211088Smjacob				/* tracks per zone */
205211088Smjacob				/* ptr[2] = 0; */
206211088Smjacob				/* ptr[3] = 0; */
207211088Smjacob				/* alternate sectors per zone */
208211088Smjacob				/* ptr[4] = 0; */
209211088Smjacob				/* ptr[5] = 0; */
210211088Smjacob				/* alternate tracks per zone */
211211088Smjacob				/* ptr[6] = 0; */
212211088Smjacob				/* ptr[7] = 0; */
213211088Smjacob				/* alternate tracks per logical unit */
214211088Smjacob				/* ptr[8] = 0; */
215211088Smjacob				/* ptr[9] = 0; */
216211088Smjacob				/* sectors per track */
217211088Smjacob				ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
218211088Smjacob				ptr[11] = PSEUDO_SPT & 0xff;
219211088Smjacob				/* data bytes per physical sector */
220211088Smjacob				ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
221211088Smjacob				ptr[13] = (1 << DISK_SHIFT) & 0xff;
222211088Smjacob				/* interleave */
223211088Smjacob				/* ptr[14] = 0; */
224211088Smjacob				/* ptr[15] = 1; */
225211088Smjacob				/* track skew factor */
226211088Smjacob				/* ptr[16] = 0; */
227211088Smjacob				/* ptr[17] = 0; */
228211088Smjacob				/* cylinder skew factor */
229211088Smjacob				/* ptr[18] = 0; */
230211088Smjacob				/* ptr[19] = 0; */
231211088Smjacob				/* SSRC, HSEC, RMB, SURF */
232211088Smjacob			}
233211088Smjacob			ptr += 26;
234211088Smjacob		}
235211088Smjacob
236211088Smjacob		if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
237211088Smjacob			ptr[0] = SMS_GEOMETRY_PAGE;
238211088Smjacob			ptr[1] = 24;
239211088Smjacob			if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
240211088Smjacob				uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
241211088Smjacob				/* number of cylinders */
242211088Smjacob				ptr[2] = (cyl >> 24) & 0xff;
243211088Smjacob				ptr[3] = (cyl >> 16) & 0xff;
244211088Smjacob				ptr[4] = cyl & 0xff;
245211088Smjacob				/* number of heads */
246211088Smjacob				ptr[5] = PSEUDO_HDS;
247211088Smjacob				/* starting cylinder- write precompensation */
248211088Smjacob				/* ptr[6] = 0; */
249211088Smjacob				/* ptr[7] = 0; */
250211088Smjacob				/* ptr[8] = 0; */
251211088Smjacob				/* starting cylinder- reduced write current */
252211088Smjacob				/* ptr[9] = 0; */
253211088Smjacob				/* ptr[10] = 0; */
254211088Smjacob				/* ptr[11] = 0; */
255211088Smjacob				/* drive step rate */
256211088Smjacob				/* ptr[12] = 0; */
257211088Smjacob				/* ptr[13] = 0; */
258211088Smjacob				/* landing zone cylinder */
259211088Smjacob				/* ptr[14] = 0; */
260211088Smjacob				/* ptr[15] = 0; */
261211088Smjacob				/* ptr[16] = 0; */
262211088Smjacob				/* RPL */
263211088Smjacob				/* ptr[17] = 0; */
264211088Smjacob				/* rotational offset */
265211088Smjacob				/* ptr[18] = 0; */
266211088Smjacob				/* medium rotation rate -  7200 RPM */
267211088Smjacob				ptr[20] = 0x1c;
268211088Smjacob				ptr[21] = 0x20;
269211088Smjacob			}
270211088Smjacob			ptr += 26;
271211088Smjacob		}
272211088Smjacob
273211088Smjacob		if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
274211088Smjacob			ptr[0] = SMS_CACHE_PAGE;
275211088Smjacob			ptr[1] = 18;
276211088Smjacob			ptr[2] = 1 << 2;
277211088Smjacob			ptr += 20;
278211088Smjacob		}
279211088Smjacob
280211088Smjacob		if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
281211088Smjacob			ptr[0] = SMS_CONTROL_MODE_PAGE;
282211088Smjacob			ptr[1] = 10;
283211088Smjacob			if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
284211088Smjacob				ptr[3] = 1 << 4; /* unrestricted reordering allowed */
285211088Smjacob				ptr[8] = 0x75;   /* 30000 ms */
286211088Smjacob				ptr[9] = 0x30;
287211088Smjacob			}
288211088Smjacob			ptr += 12;
289211088Smjacob		}
290211088Smjacob		nbyte = (char *)ptr - &junk[0];
291211088Smjacob		ptr[0] = nbyte - 4;
292211088Smjacob
293211088Smjacob		if (cdb[0] == MODE_SENSE) {
294211088Smjacob			data_len = min(cdb[4], csio->dxfer_len);
295211088Smjacob		} else {
296211088Smjacob			uint16_t tw = (cdb[7] << 8) | cdb[8];
297211088Smjacob			data_len = min(tw, csio->dxfer_len);
298211088Smjacob		}
299211088Smjacob		data_len = min(data_len, nbyte);
300211088Smjacob		if (data_len) {
301211088Smjacob			memcpy(csio->data_ptr, junk, data_len);
302211088Smjacob		}
303211088Smjacob		csio->resid = csio->dxfer_len - data_len;
304211088Smjacob		break;
305211088Smjacob	}
306211088Smjacob	case READ_6:
307211088Smjacob	case READ_10:
308211088Smjacob	case READ_12:
309211088Smjacob	case READ_16:
310211088Smjacob	case WRITE_6:
311211088Smjacob	case WRITE_10:
312211088Smjacob	case WRITE_12:
313211088Smjacob	case WRITE_16:
314211088Smjacob		if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
315211088Smjacob			vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
316211088Smjacob			break;
317211088Smjacob		}
318211183Smjacob		blkcmd++;
319211183Smjacob		if (++vhbas->nact > vhbas->nact_high) {
320211183Smjacob			vhbas->nact_high = vhbas->nact;
321211183Smjacob			printf("%s: high block count now %d\n", __func__, vhbas->nact);
322211183Smjacob		}
323211088Smjacob		if (data_len) {
324211088Smjacob			if ((cdb[0] & 0xf) == 8) {
325211088Smjacob				memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
326211088Smjacob			} else {
327211088Smjacob				memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
328211088Smjacob			}
329211088Smjacob			csio->resid = csio->dxfer_len - data_len;
330211088Smjacob		} else {
331211088Smjacob			csio->resid = csio->dxfer_len;
332211088Smjacob		}
333211088Smjacob		break;
334211088Smjacob
335211088Smjacob	case READ_CAPACITY:
336211088Smjacob		if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
337211088Smjacob			vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
338211088Smjacob			break;
339211088Smjacob		}
340211088Smjacob		if (cdb[8] & 0x1) { /* PMI */
341211088Smjacob			csio->data_ptr[0] = 0xff;
342211088Smjacob			csio->data_ptr[1] = 0xff;
343211088Smjacob			csio->data_ptr[2] = 0xff;
344211088Smjacob			csio->data_ptr[3] = 0xff;
345211088Smjacob		} else {
346211088Smjacob			uint64_t last_blk = DISK_NBLKS - 1;
347211088Smjacob			if (last_blk < 0xffffffffULL) {
348211088Smjacob			    csio->data_ptr[0] = (last_blk >> 24) & 0xff;
349211088Smjacob			    csio->data_ptr[1] = (last_blk >> 16) & 0xff;
350211088Smjacob			    csio->data_ptr[2] = (last_blk >>  8) & 0xff;
351211088Smjacob			    csio->data_ptr[3] = (last_blk) & 0xff;
352211088Smjacob			} else {
353211088Smjacob			    csio->data_ptr[0] = 0xff;
354211088Smjacob			    csio->data_ptr[1] = 0xff;
355211088Smjacob			    csio->data_ptr[2] = 0xff;
356211088Smjacob			    csio->data_ptr[3] = 0xff;
357211088Smjacob			}
358211088Smjacob		}
359211088Smjacob		csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
360211088Smjacob		csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
361211088Smjacob		csio->data_ptr[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
362211088Smjacob		csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
363211088Smjacob		break;
364211088Smjacob	default:
365211088Smjacob		vhba_default_cmd(csio, MAX_LUN, NULL);
366211088Smjacob		break;
367211088Smjacob	}
368211088Smjacob	if (csio->scsi_status != SCSI_STATUS_OK) {
369211088Smjacob		camstatus = CAM_SCSI_STATUS_ERROR;
370211088Smjacob		if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
371211088Smjacob			camstatus |= CAM_AUTOSNS_VALID;
372211088Smjacob		}
373211088Smjacob	} else {
374211088Smjacob		csio->scsi_status = SCSI_STATUS_OK;
375211088Smjacob		camstatus = CAM_REQ_CMP;
376211088Smjacob	}
377211088Smjacob	vhba_set_status(&csio->ccb_h, camstatus);
378211183Smjacob	if (blkcmd) {
379211183Smjacob		int ticks;
380211183Smjacob		struct timeval t;
381211183Smjacob
382211183Smjacob		TAILQ_INSERT_TAIL(&vhbas->inproc, &csio->ccb_h, sim_links.tqe);
383211183Smjacob		t.tv_sec = 0;
384211183Smjacob		t.tv_usec = (500 + arc4random());
385211183Smjacob		if (t.tv_usec > 10000) {
386211183Smjacob			t.tv_usec = 10000;
387211183Smjacob		}
388211183Smjacob		ticks = tvtohz(&t);
389211183Smjacob		csio->ccb_h.timeout_ch = timeout(vhba_iodelay, &csio->ccb_h, ticks);
390211183Smjacob	} else {
391211183Smjacob		TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
392211183Smjacob	}
393211088Smjacob}
394211088Smjacob
395211183Smjacobstatic void
396211183Smjacobvhba_iodelay(void *arg)
397211183Smjacob{
398211183Smjacob	struct ccb_hdr *ccbh = arg;
399211183Smjacob	mptest_t *vhbas = ccbh->sim_priv.entries[0].ptr;
400211088Smjacob
401211183Smjacob	mtx_lock(&vhbas->vhba->lock);
402211183Smjacob	TAILQ_REMOVE(&vhbas->inproc, ccbh, sim_links.tqe);
403211183Smjacob	TAILQ_INSERT_TAIL(&vhbas->vhba->done, ccbh, sim_links.tqe);
404211183Smjacob	vhbas->nact -= 1;
405211183Smjacob	vhba_kick(vhbas->vhba);
406211183Smjacob	mtx_unlock(&vhbas->vhba->lock);
407211183Smjacob}
408211183Smjacob
409211088Smjacobstatic void
410211088Smjacobvhba_timer(void *arg)
411211088Smjacob{
412211088Smjacob	int lun;
413211088Smjacob	vhba_softc_t *vhba = arg;
414211088Smjacob	mptest_t *vhbas = vhba->private;
415211088Smjacob	if (vhba_stop_lun) {
416211088Smjacob		lun = (vhba_stop_lun & 1)? 0 : 1;
417211088Smjacob		if (lun == 0 || lun == 1) {
418211088Smjacob			if (vhbas->luns[lun]) {
419211088Smjacob				struct cam_path *tp;
420211088Smjacob				if (vhba_notify_stop) {
421211088Smjacob					if (xpt_create_path(&tp, xpt_periph, cam_sim_path(vhba->sim), 0, lun) != CAM_REQ_CMP) {
422211088Smjacob						goto out;
423211088Smjacob					}
424211088Smjacob					vhbas->luns[lun] = 0;
425211088Smjacob					xpt_async(AC_LOST_DEVICE, tp, NULL);
426211088Smjacob					xpt_free_path(tp);
427211088Smjacob				} else {
428211088Smjacob					vhbas->luns[lun] = 0;
429211088Smjacob				}
430211088Smjacob			}
431211088Smjacob		}
432211088Smjacob		vhba_stop_lun &= ~(1 << lun);
433211088Smjacob	} else if (vhba_start_lun) {
434211088Smjacob		lun = (vhba_start_lun & 1)? 0 : 1;
435211088Smjacob		if (lun == 0 || lun == 1) {
436211088Smjacob			if (vhbas->luns[lun] == 0) {
437211088Smjacob				if (vhba_notify_start) {
438211088Smjacob					union ccb *ccb;
439211088Smjacob					ccb = xpt_alloc_ccb_nowait();
440211088Smjacob					if (ccb == NULL) {
441211088Smjacob						goto out;
442211088Smjacob					}
443211088Smjacob					if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(vhba->sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
444211088Smjacob						xpt_free_ccb(ccb);
445211088Smjacob						goto out;
446211088Smjacob					}
447211088Smjacob					vhbas->luns[lun] = 1;
448211088Smjacob					xpt_rescan(ccb);
449211088Smjacob				} else {
450211088Smjacob					vhbas->luns[lun] = 1;
451211088Smjacob				}
452211088Smjacob			}
453211088Smjacob		}
454211088Smjacob		vhba_start_lun &= ~(1 << lun);
455211088Smjacob	}
456211088Smjacobout:
457211088Smjacob	callout_reset(&vhbas->tick, VMP_TIME, vhba_timer, vhba);
458211088Smjacob}
459211088SmjacobDEV_MODULE(vhba_mptest, vhba_modprobe, NULL);
460