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