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
28 * A VHBA device to test REPORT LUN functionality.
37 #define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
40 #define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
47 uint8_t rpbitmap[MAX_LUN >> 3];
50 static void vhba_task(void *, int);
51 static void vhbarptluns_act(vhbarptluns_t *, struct ccb_scsiio *);
54 vhba_init(vhba_softc_t *vhba)
56 static vhbarptluns_t vhbas;
61 vhbas.disk_size = DISK_SIZE << 20;
62 vhbas.disk = malloc(vhbas.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
63 vhba->private = &vhbas;
64 printf("setting luns");
66 if (now.tv_usec & 0x1) {
67 vhbas.rpbitmap[0] |= 1;
69 for (i = 1; i < 8; i++) {
70 if (arc4random() & 1) {
72 vhbas.rpbitmap[0] |= (1 << i);
75 for (i = 8; i < MAX_LUN; i++) {
76 if ((arc4random() % i) == 0) {
77 vhbas.rpbitmap[i >> 3] |= (1 << (i & 0x7));
82 TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
86 vhba_fini(vhba_softc_t *vhba)
88 vhbarptluns_t *vhbas = vhba->private;
90 free(vhbas->disk, M_DEVBUF);
94 vhba_kick(vhba_softc_t *vhba)
96 vhbarptluns_t *vhbas = vhba->private;
97 taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
101 vhba_task(void *arg, int pending)
103 vhbarptluns_t *vhbas = arg;
104 struct ccb_hdr *ccbh;
106 mtx_lock(&vhbas->vhba->lock);
107 while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
108 TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
109 vhbarptluns_act(vhbas, (struct ccb_scsiio *)ccbh);
111 while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
112 TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
113 xpt_done((union ccb *)ccbh);
115 mtx_unlock(&vhbas->vhba->lock);
119 vhbarptluns_act(vhbarptluns_t *vhbas, struct ccb_scsiio *csio)
122 uint8_t *cdb, *ptr, status;
125 int i, attached_lun = 0;
128 status = SCSI_STATUS_OK;
130 memset(&csio->sense_data, 0, sizeof (csio->sense_data));
131 cdb = csio->cdb_io.cdb_bytes;
133 if (csio->ccb_h.target_id >= MAX_TGT) {
134 csio->ccb_h.status = CAM_SEL_TIMEOUT;
135 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
139 if (csio->ccb_h.target_lun < MAX_LUN) {
140 i = csio->ccb_h.target_lun & 0x7;
141 if (vhbas->rpbitmap[csio->ccb_h.target_lun >> 3] & (1 << i)) {
145 if (attached_lun == 0 && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
146 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
147 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
156 uint8_t page = cdb[2] & SMS_PAGE_CODE;
157 uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
160 case SMS_FORMAT_DEVICE_PAGE:
161 case SMS_GEOMETRY_PAGE:
163 case SMS_CONTROL_MODE_PAGE:
164 case SMS_ALL_PAGES_PAGE:
167 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
168 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
171 memset(junk, 0, sizeof (junk));
172 if (cdb[1] & SMS_DBD) {
177 ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
178 ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
179 ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
180 ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
182 ptr[8] = (DISK_NBLKS >> 24) & 0xff;
183 ptr[9] = (DISK_NBLKS >> 16) & 0xff;
184 ptr[10] = (DISK_NBLKS >> 8) & 0xff;
185 ptr[11] = DISK_NBLKS & 0xff;
189 if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
190 ptr[0] = SMS_FORMAT_DEVICE_PAGE;
192 if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
193 /* tracks per zone */
196 /* alternate sectors per zone */
199 /* alternate tracks per zone */
202 /* alternate tracks per logical unit */
205 /* sectors per track */
206 ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
207 ptr[11] = PSEUDO_SPT & 0xff;
208 /* data bytes per physical sector */
209 ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
210 ptr[13] = (1 << DISK_SHIFT) & 0xff;
214 /* track skew factor */
217 /* cylinder skew factor */
220 /* SSRC, HSEC, RMB, SURF */
225 if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
226 ptr[0] = SMS_GEOMETRY_PAGE;
228 if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
229 uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
230 /* number of cylinders */
231 ptr[2] = (cyl >> 24) & 0xff;
232 ptr[3] = (cyl >> 16) & 0xff;
234 /* number of heads */
236 /* starting cylinder- write precompensation */
240 /* starting cylinder- reduced write current */
244 /* drive step rate */
247 /* landing zone cylinder */
253 /* rotational offset */
255 /* medium rotation rate - 7200 RPM */
262 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
263 ptr[0] = SMS_CACHE_PAGE;
269 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
270 ptr[0] = SMS_CONTROL_MODE_PAGE;
272 if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
273 ptr[3] = 1 << 4; /* unrestricted reordering allowed */
274 ptr[8] = 0x75; /* 30000 ms */
279 nbyte = (char *)ptr - &junk[0];
282 if (cdb[0] == MODE_SENSE) {
283 data_len = min(cdb[4], csio->dxfer_len);
285 uint16_t tw = (cdb[7] << 8) | cdb[8];
286 data_len = min(tw, csio->dxfer_len);
288 data_len = min(data_len, nbyte);
290 memcpy(csio->data_ptr, junk, data_len);
292 csio->resid = csio->dxfer_len - data_len;
303 if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
304 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
308 if ((cdb[0] & 0xf) == 8) {
309 memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
311 memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
313 csio->resid = csio->dxfer_len - data_len;
315 csio->resid = csio->dxfer_len;
321 if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
322 vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
325 if (cdb[8] & 0x1) { /* PMI */
326 csio->data_ptr[0] = 0xff;
327 csio->data_ptr[1] = 0xff;
328 csio->data_ptr[2] = 0xff;
329 csio->data_ptr[3] = 0xff;
331 uint64_t last_blk = DISK_NBLKS - 1;
332 if (last_blk < 0xffffffffULL) {
333 csio->data_ptr[0] = (last_blk >> 24) & 0xff;
334 csio->data_ptr[1] = (last_blk >> 16) & 0xff;
335 csio->data_ptr[2] = (last_blk >> 8) & 0xff;
336 csio->data_ptr[3] = (last_blk) & 0xff;
338 csio->data_ptr[0] = 0xff;
339 csio->data_ptr[1] = 0xff;
340 csio->data_ptr[2] = 0xff;
341 csio->data_ptr[3] = 0xff;
344 csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
345 csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
346 csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
347 csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
351 vhba_default_cmd(csio, MAX_LUN, vhbas->rpbitmap);
354 csio->ccb_h.status &= ~CAM_STATUS_MASK;
355 if (csio->scsi_status != SCSI_STATUS_OK) {
356 csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
357 if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
358 csio->ccb_h.status |= CAM_AUTOSNS_VALID;
361 csio->scsi_status = SCSI_STATUS_OK;
362 csio->ccb_h.status |= CAM_REQ_CMP;
364 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
366 DEV_MODULE(vhba_rtpluns, vhba_modprobe, NULL);