]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/vhba/rptluns/vhba_rptluns.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / vhba / rptluns / vhba_rptluns.c
1 /*-
2  * Copyright (c) 2010 by Panasas, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26 /* $FreeBSD$ */
27 /*
28  * A VHBA device to test REPORT LUN functionality.
29  */
30 #include "vhba.h"
31
32 #define MAX_TGT         1
33 #define MAX_LUN         1024
34
35 #define DISK_SIZE       32
36 #define DISK_SHIFT      9
37 #define DISK_NBLKS      ((DISK_SIZE << 20) >> DISK_SHIFT)
38 #define PSEUDO_SPT      64
39 #define PSEUDO_HDS      64
40 #define PSEUDO_SPC      (PSEUDO_SPT * PSEUDO_HDS)
41
42 typedef struct {
43         vhba_softc_t *  vhba;
44         uint8_t *       disk;
45         size_t          disk_size;
46         struct task     qt;
47         uint8_t         rpbitmap[MAX_LUN >> 3];
48 } vhbarptluns_t;
49
50 static void vhba_task(void *, int);
51 static void vhbarptluns_act(vhbarptluns_t *, struct ccb_scsiio *);
52
53 void
54 vhba_init(vhba_softc_t *vhba)
55 {
56         static vhbarptluns_t vhbas;
57         struct timeval now;
58         int i;
59
60         vhbas.vhba = vhba;
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");
65         getmicrotime(&now);
66         if (now.tv_usec & 0x1) {
67                 vhbas.rpbitmap[0] |= 1;
68         }
69         for (i = 1; i < 8; i++) {
70                 if (arc4random() & 1) {
71                         printf(" %d", i);
72                         vhbas.rpbitmap[0] |= (1 << i);
73                 }
74         }
75         for (i = 8; i < MAX_LUN; i++) {
76                 if ((arc4random() % i) == 0) {
77                         vhbas.rpbitmap[i >> 3] |= (1 << (i & 0x7));
78                         printf(" %d", i);
79                 }
80         }
81         printf("\n");
82         TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
83 }
84
85 void
86 vhba_fini(vhba_softc_t *vhba)
87 {
88         vhbarptluns_t *vhbas = vhba->private;
89         vhba->private = NULL;
90         free(vhbas->disk, M_DEVBUF);
91 }
92
93 void
94 vhba_kick(vhba_softc_t *vhba)
95 {
96         vhbarptluns_t *vhbas = vhba->private;
97         taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
98 }
99
100 static void
101 vhba_task(void *arg, int pending)
102 {
103         vhbarptluns_t *vhbas = arg;
104         struct ccb_hdr *ccbh;
105
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);
110         }
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);
114         }
115         mtx_unlock(&vhbas->vhba->lock);
116 }
117
118 static void
119 vhbarptluns_act(vhbarptluns_t *vhbas, struct ccb_scsiio *csio)
120 {
121         char junk[128];
122         uint8_t *cdb, *ptr, status;
123         uint32_t data_len;
124         uint64_t off;
125         int i, attached_lun = 0;
126             
127         data_len = 0;
128         status = SCSI_STATUS_OK;
129
130         memset(&csio->sense_data, 0, sizeof (csio->sense_data));
131         cdb = csio->cdb_io.cdb_bytes;
132
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);
136                 return;
137         }
138
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)) {
142                         attached_lun = 1;
143                 }
144         }
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);
148                 return;
149         }
150
151         switch (cdb[0]) {
152         case MODE_SENSE:
153         case MODE_SENSE_10:
154         {
155                 unsigned int nbyte;
156                 uint8_t page = cdb[2] & SMS_PAGE_CODE;
157                 uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
158
159                 switch (page) {
160                 case SMS_FORMAT_DEVICE_PAGE:
161                 case SMS_GEOMETRY_PAGE:
162                 case SMS_CACHE_PAGE:
163                 case SMS_CONTROL_MODE_PAGE:
164                 case SMS_ALL_PAGES_PAGE:
165                         break;
166                 default:
167                         vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
168                         TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
169                         return;
170                 }
171                 memset(junk, 0, sizeof (junk));
172                 if (cdb[1] & SMS_DBD) {
173                         ptr = &junk[4];
174                 } else {
175                         ptr = junk;
176                         ptr[3] = 8;
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;
181
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;
186                         ptr += 12;
187                 }
188
189                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
190                         ptr[0] = SMS_FORMAT_DEVICE_PAGE;
191                         ptr[1] = 24;
192                         if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
193                                 /* tracks per zone */
194                                 /* ptr[2] = 0; */
195                                 /* ptr[3] = 0; */
196                                 /* alternate sectors per zone */
197                                 /* ptr[4] = 0; */
198                                 /* ptr[5] = 0; */
199                                 /* alternate tracks per zone */
200                                 /* ptr[6] = 0; */
201                                 /* ptr[7] = 0; */
202                                 /* alternate tracks per logical unit */
203                                 /* ptr[8] = 0; */
204                                 /* ptr[9] = 0; */
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;
211                                 /* interleave */
212                                 /* ptr[14] = 0; */
213                                 /* ptr[15] = 1; */
214                                 /* track skew factor */
215                                 /* ptr[16] = 0; */
216                                 /* ptr[17] = 0; */
217                                 /* cylinder skew factor */
218                                 /* ptr[18] = 0; */
219                                 /* ptr[19] = 0; */
220                                 /* SSRC, HSEC, RMB, SURF */
221                         }
222                         ptr += 26;
223                 }
224
225                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
226                         ptr[0] = SMS_GEOMETRY_PAGE;
227                         ptr[1] = 24;
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;
233                                 ptr[4] = cyl & 0xff;
234                                 /* number of heads */
235                                 ptr[5] = PSEUDO_HDS;
236                                 /* starting cylinder- write precompensation */
237                                 /* ptr[6] = 0; */
238                                 /* ptr[7] = 0; */
239                                 /* ptr[8] = 0; */
240                                 /* starting cylinder- reduced write current */
241                                 /* ptr[9] = 0; */
242                                 /* ptr[10] = 0; */
243                                 /* ptr[11] = 0; */
244                                 /* drive step rate */
245                                 /* ptr[12] = 0; */
246                                 /* ptr[13] = 0; */
247                                 /* landing zone cylinder */
248                                 /* ptr[14] = 0; */
249                                 /* ptr[15] = 0; */
250                                 /* ptr[16] = 0; */
251                                 /* RPL */
252                                 /* ptr[17] = 0; */
253                                 /* rotational offset */
254                                 /* ptr[18] = 0; */
255                                 /* medium rotation rate -  7200 RPM */
256                                 ptr[20] = 0x1c;
257                                 ptr[21] = 0x20;
258                         }
259                         ptr += 26;
260                 }
261
262                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
263                         ptr[0] = SMS_CACHE_PAGE;
264                         ptr[1] = 18;
265                         ptr[2] = 1 << 2;
266                         ptr += 20;
267                 }
268
269                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
270                         ptr[0] = SMS_CONTROL_MODE_PAGE;
271                         ptr[1] = 10;
272                         if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
273                                 ptr[3] = 1 << 4; /* unrestricted reordering allowed */
274                                 ptr[8] = 0x75;   /* 30000 ms */
275                                 ptr[9] = 0x30;
276                         }
277                         ptr += 12;
278                 }
279                 nbyte = (char *)ptr - &junk[0];
280                 ptr[0] = nbyte - 4;
281
282                 if (cdb[0] == MODE_SENSE) {
283                         data_len = min(cdb[4], csio->dxfer_len);
284                 } else {
285                         uint16_t tw = (cdb[7] << 8) | cdb[8];
286                         data_len = min(tw, csio->dxfer_len);
287                 }
288                 data_len = min(data_len, nbyte);
289                 if (data_len) {
290                         memcpy(csio->data_ptr, junk, data_len);
291                 }
292                 csio->resid = csio->dxfer_len - data_len;
293                 break;
294         }
295         case READ_6:
296         case READ_10:
297         case READ_12:
298         case READ_16:
299         case WRITE_6:
300         case WRITE_10:
301         case WRITE_12:
302         case WRITE_16:
303                 if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
304                         vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
305                         break;
306                 }
307                 if (data_len) {
308                         if ((cdb[0] & 0xf) == 8) {
309                                 memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
310                         } else {
311                                 memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
312                         }
313                         csio->resid = csio->dxfer_len - data_len;
314                 } else {
315                         csio->resid = csio->dxfer_len;
316                 }
317                 break;
318                 break;
319
320         case READ_CAPACITY:
321                 if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
322                         vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
323                         break;
324                 }
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;
330                 } else {
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;
337                         } else {
338                             csio->data_ptr[0] = 0xff;
339                             csio->data_ptr[1] = 0xff;
340                             csio->data_ptr[2] = 0xff;
341                             csio->data_ptr[3] = 0xff;
342                         }
343                 }
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;
348                 break;
349
350         default:
351                 vhba_default_cmd(csio, MAX_LUN, vhbas->rpbitmap);
352                 break;
353         }
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;
359                 }
360         } else {
361                 csio->scsi_status = SCSI_STATUS_OK;
362                 csio->ccb_h.status |= CAM_REQ_CMP;
363         }
364         TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
365 }
366 DEV_MODULE(vhba_rtpluns, vhba_modprobe, NULL);