2 * Copyright (c) 2010 by Panasas, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice immediately at the beginning of the file, without modification,
10 * this list of conditions, and the following disclaimer.
11 * 2. The name of the author may not be used to endorse or promote products
12 * derived from this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Virtual HBA infrastructure, to be used for testing as well as other cute hacks.
30 static vhba_softc_t *vhba;
33 #define VHBA_MOD "vhba"
36 static void vhba_action(struct cam_sim *, union ccb *);
37 static void vhba_poll(struct cam_sim *);
40 vhba_attach(vhba_softc_t *vhba)
42 TAILQ_INIT(&vhba->actv);
43 TAILQ_INIT(&vhba->done);
44 vhba->devq = cam_simq_alloc(VHBA_MAXCMDS);
45 if (vhba->devq == NULL) {
48 vhba->sim = cam_sim_alloc(vhba_action, vhba_poll, VHBA_MOD, vhba, 0, &vhba->lock, VHBA_MAXCMDS, VHBA_MAXCMDS, vhba->devq);
49 if (vhba->sim == NULL) {
50 cam_simq_free(vhba->devq);
54 mtx_lock(&vhba->lock);
55 if (xpt_bus_register(vhba->sim, 0, 0) != CAM_SUCCESS) {
56 cam_sim_free(vhba->sim, TRUE);
57 mtx_unlock(&vhba->lock);
60 mtx_unlock(&vhba->lock);
65 vhba_detach(vhba_softc_t *vhba)
68 * We can't be called with anything queued up.
71 xpt_bus_deregister(cam_sim_path(vhba->sim));
72 cam_sim_free(vhba->sim, TRUE);
76 vhba_poll(struct cam_sim *sim)
78 vhba_softc_t *vhba = cam_sim_softc(sim);
83 vhba_action(struct cam_sim *sim, union ccb *ccb)
85 struct ccb_trans_settings *cts;
88 vhba = cam_sim_softc(sim);
89 if (vhba->private == NULL) {
90 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
94 switch (ccb->ccb_h.func_code) {
96 ccb->ccb_h.status &= ~CAM_STATUS_MASK;
97 ccb->ccb_h.status |= CAM_REQ_INPROG;
98 TAILQ_INSERT_TAIL(&vhba->actv, &ccb->ccb_h, sim_links.tqe);
103 ccb->ccb_h.status = CAM_REQ_CMP;
106 case XPT_GET_TRAN_SETTINGS:
108 cts->protocol_version = SCSI_REV_SPC3;
109 cts->protocol = PROTO_SCSI;
110 cts->transport_version = 0;
111 cts->transport = XPORT_PPB;
112 ccb->ccb_h.status = CAM_REQ_CMP;
115 case XPT_CALC_GEOMETRY:
116 cam_calc_geometry(&ccb->ccg, 1);
119 case XPT_RESET_BUS: /* Reset the specified bus */
120 ccb->ccb_h.status = CAM_REQ_CMP;
123 case XPT_PATH_INQ: /* Path routing inquiry */
125 struct ccb_pathinq *cpi = &ccb->cpi;
127 cpi->version_num = 1;
128 cpi->max_target = VHBA_MAXTGT - 1;
129 cpi->max_lun = 16383;
130 cpi->hba_misc = PIM_NOBUSRESET;
131 cpi->initiator_id = cpi->max_target + 1;
132 cpi->transport = XPORT_PPB;
133 cpi->base_transfer_speed = 1000000;
134 cpi->protocol = PROTO_SCSI;
135 cpi->protocol_version = SCSI_REV_SPC3;
136 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
137 strlcpy(cpi->hba_vid, "FakeHBA", HBA_IDLEN);
138 strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
139 cpi->unit_number = cam_sim_unit(sim);
140 cpi->ccb_h.status = CAM_REQ_CMP;
144 ccb->ccb_h.status = CAM_REQ_INVALID;
154 vhba_fill_sense(struct ccb_scsiio *csio, uint8_t key, uint8_t asc, uint8_t ascq)
156 csio->ccb_h.status = CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
157 csio->scsi_status = SCSI_STATUS_CHECK_COND;
158 csio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
159 csio->sense_data.flags = key;
160 csio->sense_data.extra_len = 10;
161 csio->sense_data.add_sense_code = asc;
162 csio->sense_data.add_sense_code_qual = ascq;
163 csio->sense_len = sizeof (csio->sense_data);
167 vhba_rwparm(uint8_t *cdb, uint64_t *offset, uint32_t *tl, uint64_t nblks, uint32_t blk_shift)
175 cnt = (((uint32_t)cdb[10]) << 24) |
176 (((uint32_t)cdb[11]) << 16) |
177 (((uint32_t)cdb[12]) << 8) |
180 lba = (((uint64_t)cdb[2]) << 56) |
181 (((uint64_t)cdb[3]) << 48) |
182 (((uint64_t)cdb[4]) << 40) |
183 (((uint64_t)cdb[5]) << 32) |
184 (((uint64_t)cdb[6]) << 24) |
185 (((uint64_t)cdb[7]) << 16) |
186 (((uint64_t)cdb[8]) << 8) |
191 cnt = (((uint32_t)cdb[6]) << 16) |
192 (((uint32_t)cdb[7]) << 8) |
195 lba = (((uint32_t)cdb[2]) << 24) |
196 (((uint32_t)cdb[3]) << 16) |
197 (((uint32_t)cdb[4]) << 8) |
202 cnt = (((uint32_t)cdb[7]) << 8) |
205 lba = (((uint32_t)cdb[2]) << 24) |
206 (((uint32_t)cdb[3]) << 16) |
207 (((uint32_t)cdb[4]) << 8) |
216 lba = (((uint32_t)cdb[1] & 0x1f) << 16) |
217 (((uint32_t)cdb[2]) << 8) |
224 if (lba + cnt > nblks) {
227 *tl = cnt << blk_shift;
228 *offset = lba << blk_shift;
233 vhba_default_cmd(struct ccb_scsiio *csio, lun_id_t max_lun, uint8_t *sparse_lun_map)
236 const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = {
237 0x7f, 0x0, SCSI_REV_SPC3, 0x2, 32, 0, 0, 0x32,
238 'P', 'A', 'N', 'A', 'S', 'A', 'S', ' ',
239 'N', 'U', 'L', 'L', ' ', 'D', 'E', 'V',
240 'I', 'C', 'E', ' ', ' ', ' ', ' ', ' ',
243 const uint8_t iqd[SHORT_INQUIRY_LENGTH] = {
244 0, 0x0, SCSI_REV_SPC3, 0x2, 32, 0, 0, 0x32,
245 'P', 'A', 'N', 'A', 'S', 'A', 'S', ' ',
246 'V', 'I', 'R', 'T', ' ', 'M', 'E', 'M',
247 'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
250 const uint8_t vp0data[6] = { 0, 0, 0, 0x2, 0, 0x80 };
251 const uint8_t vp80data[36] = { 0, 0x80, 0, 0x20 };
253 uint8_t *cdb, *ptr, status;
254 uint32_t data_len, nlun;
257 status = SCSI_STATUS_OK;
259 memset(&csio->sense_data, 0, sizeof (csio->sense_data));
260 cdb = csio->cdb_io.cdb_bytes;
263 if (csio->ccb_h.target_lun >= max_lun) {
265 } else if (sparse_lun_map) {
266 i = csio->ccb_h.target_lun & 0x7;
267 if ((sparse_lun_map[csio->ccb_h.target_lun >> 3] & (1 << i)) == 0) {
271 if (attached_lun == 0 && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
272 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
278 data_len = csio->dxfer_len;
279 if (cdb[4] < csio->dxfer_len)
282 memset(junk, 0, sizeof (junk));
283 junk[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
284 junk[2] = SSD_KEY_NO_SENSE;
286 memcpy(csio->data_ptr, junk,
287 (data_len > sizeof junk)? sizeof junk : data_len);
289 csio->resid = csio->dxfer_len - data_len;
293 if ((cdb[1] & 0x1f) == SI_EVPD) {
294 if ((cdb[2] != 0 && cdb[2] != 0x80) || cdb[3] || cdb[5]) {
297 } else if ((cdb[1] & 0x1f) || cdb[2] || cdb[3] || cdb[5]) {
301 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
304 if (attached_lun == 0) {
306 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
309 memcpy(junk, niliqd, sizeof (niliqd));
310 data_len = sizeof (niliqd);
311 } else if (cdb[1] & 0x1f) {
313 memcpy(junk, vp0data, sizeof (vp0data));
314 data_len = sizeof (vp0data);
316 memcpy(junk, vp80data, sizeof (vp80data));
317 snprintf(&junk[4], sizeof (vp80data) - 4, "TGT%dLUN%d", csio->ccb_h.target_id, csio->ccb_h.target_lun);
318 for (i = 0; i < sizeof (vp80data); i++) {
324 data_len = sizeof (vp80data);
326 memcpy(junk, iqd, sizeof (iqd));
327 data_len = sizeof (iqd);
329 if (data_len > cdb[4]) {
333 memcpy(csio->data_ptr, junk, data_len);
335 csio->resid = csio->dxfer_len - data_len;
337 case TEST_UNIT_READY:
338 case SYNCHRONIZE_CACHE:
345 if (csio->dxfer_len) {
346 memset(csio->data_ptr, 0, csio->dxfer_len);
349 for (nlun = i = 0; i < max_lun; i++) {
350 if (sparse_lun_map) {
351 if ((sparse_lun_map[i >> 3] & (1 << (i & 0x7))) == 0) {
355 ptr = &csio->data_ptr[8 + ((nlun++) << 3)];
356 if ((ptr + 8) > &csio->data_ptr[csio->dxfer_len]) {
360 ptr[0] = 0x40 | ((i >> 8) & 0x3f);
364 junk[0] = (nlun << 3) >> 24;
365 junk[1] = (nlun << 3) >> 16;
366 junk[2] = (nlun << 3) >> 8;
367 junk[3] = (nlun << 3);
368 memset(junk+4, 0, 4);
369 if (csio->dxfer_len) {
372 amt = MIN(csio->dxfer_len, 8);
373 memcpy(csio->data_ptr, junk, amt);
374 amt = MIN((nlun << 3) + 8, csio->dxfer_len);
375 csio->resid = csio->dxfer_len - amt;
380 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x20, 0x0);
386 vhba_set_status(struct ccb_hdr *ccbh, cam_status status)
388 ccbh->status &= ~CAM_STATUS_MASK;
389 ccbh->status |= status;
390 if (status != CAM_REQ_CMP) {
391 if ((ccbh->status & CAM_DEV_QFRZN) == 0) {
392 ccbh->status |= CAM_DEV_QFRZN;
393 xpt_freeze_devq(ccbh->path, 1);
399 vhba_modprobe(module_t mod, int cmd, void *arg)
405 vhba = malloc(sizeof (*vhba), M_DEVBUF, M_WAITOK|M_ZERO);
406 mtx_init(&vhba->lock, "vhba", NULL, MTX_DEF);
407 error = vhba_attach(vhba);
409 mtx_destroy(&vhba->lock);
410 free(vhba, M_DEVBUF);
414 mtx_lock(&vhba->lock);
415 if (TAILQ_FIRST(&vhba->done) || TAILQ_FIRST(&vhba->actv)) {
417 mtx_unlock(&vhba->lock);
421 mtx_unlock(&vhba->lock);
422 mtx_destroy(&vhba->lock);
423 free(vhba, M_DEVBUF);