]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/vhba/faulty/vhba_faulty.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / vhba / faulty / vhba_faulty.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  * "Faulty" Device. Victimize random commands with a Selection Timeout.
29  */
30 #include "vhba.h"
31
32 #define MAX_TGT         VHBA_MAXTGT
33 #define MAX_LUN         4
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         uint32_t        ctr;
47         uint32_t        dead;
48         struct task     qt;
49 } faulty_t;
50
51 static void vhba_task(void *, int);
52 static void faulty_act(faulty_t *, struct ccb_scsiio *);
53
54 void
55 vhba_init(vhba_softc_t *vhba)
56 {
57         static faulty_t vhbastatic;
58         vhbastatic.vhba = vhba;
59         vhbastatic.disk_size = DISK_SIZE << 20;
60         vhbastatic.disk = malloc(vhbastatic.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
61         vhba->private = &vhbastatic;
62         vhbastatic.ctr = (arc4random() & 0xffff) + 1;
63         TASK_INIT(&vhbastatic.qt, 0, vhba_task, &vhbastatic);
64 }
65
66
67 void
68 vhba_fini(vhba_softc_t *vhba)
69 {
70         faulty_t *vhbas = vhba->private;
71         vhba->private = NULL;
72         free(vhbas->disk, M_DEVBUF);
73 }
74
75 void
76 vhba_kick(vhba_softc_t *vhba)
77 {
78         faulty_t *vhbas = vhba->private;
79         taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
80 }
81
82 static void
83 vhba_task(void *arg, int pending)
84 {
85         faulty_t *vhbas = arg;
86         struct ccb_hdr *ccbh;
87
88         mtx_lock(&vhbas->vhba->lock);
89         while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
90                 TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
91                 faulty_act(vhbas, (struct ccb_scsiio *)ccbh);
92                 if (--vhbas->ctr == 0) {
93                         vhbas->dead = 1;
94                         vhbas->ctr = (arc4random() & 0xff) + 1;
95                 }
96         }
97         while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
98                 TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
99                 xpt_done((union ccb *)ccbh);
100         }
101         mtx_unlock(&vhbas->vhba->lock);
102 }
103
104 static void
105 faulty_act(faulty_t *vhbas, struct ccb_scsiio *csio)
106 {
107         char junk[128];
108         cam_status camstatus;
109         uint8_t *cdb, *ptr, status;
110         uint32_t data_len;
111         uint64_t off;
112             
113         data_len = 0;
114         status = SCSI_STATUS_OK;
115
116         memset(&csio->sense_data, 0, sizeof (csio->sense_data));
117         cdb = csio->cdb_io.cdb_bytes;
118
119         if (csio->ccb_h.target_id >=  MAX_TGT) {
120                 vhba_set_status(&csio->ccb_h, CAM_SEL_TIMEOUT);
121                 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
122                 return;
123         }
124         if (vhbas->dead) {
125                 vhbas->dead = 0;
126                 vhba_set_status(&csio->ccb_h, CAM_SEL_TIMEOUT);
127                 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
128                 return;
129         }
130         if (csio->ccb_h.target_lun >= MAX_LUN && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
131                 vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
132                 TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
133                 return;
134         }
135
136         switch (cdb[0]) {
137         case MODE_SENSE:
138         case MODE_SENSE_10:
139         {
140                 unsigned int nbyte;
141                 uint8_t page = cdb[2] & SMS_PAGE_CODE;
142                 uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
143
144                 switch (page) {
145                 case SMS_FORMAT_DEVICE_PAGE:
146                 case SMS_GEOMETRY_PAGE:
147                 case SMS_CACHE_PAGE:
148                 case SMS_CONTROL_MODE_PAGE:
149                 case SMS_ALL_PAGES_PAGE:
150                         break;
151                 default:
152                         vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
153                         TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
154                         return;
155                 }
156                 memset(junk, 0, sizeof (junk));
157                 if (cdb[1] & SMS_DBD) {
158                         ptr = &junk[4];
159                 } else {
160                         ptr = junk;
161                         ptr[3] = 8;
162                         ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
163                         ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
164                         ptr[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
165                         ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
166
167                         ptr[8] = (DISK_NBLKS >> 24) & 0xff;
168                         ptr[9] = (DISK_NBLKS >> 16) & 0xff;
169                         ptr[10] = (DISK_NBLKS >> 8) & 0xff;
170                         ptr[11] = DISK_NBLKS & 0xff;
171                         ptr += 12;
172                 }
173
174                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
175                         ptr[0] = SMS_FORMAT_DEVICE_PAGE;
176                         ptr[1] = 24;
177                         if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
178                                 /* tracks per zone */
179                                 /* ptr[2] = 0; */
180                                 /* ptr[3] = 0; */
181                                 /* alternate sectors per zone */
182                                 /* ptr[4] = 0; */
183                                 /* ptr[5] = 0; */
184                                 /* alternate tracks per zone */
185                                 /* ptr[6] = 0; */
186                                 /* ptr[7] = 0; */
187                                 /* alternate tracks per logical unit */
188                                 /* ptr[8] = 0; */
189                                 /* ptr[9] = 0; */
190                                 /* sectors per track */
191                                 ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
192                                 ptr[11] = PSEUDO_SPT & 0xff;
193                                 /* data bytes per physical sector */
194                                 ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
195                                 ptr[13] = (1 << DISK_SHIFT) & 0xff;
196                                 /* interleave */
197                                 /* ptr[14] = 0; */
198                                 /* ptr[15] = 1; */
199                                 /* track skew factor */
200                                 /* ptr[16] = 0; */
201                                 /* ptr[17] = 0; */
202                                 /* cylinder skew factor */
203                                 /* ptr[18] = 0; */
204                                 /* ptr[19] = 0; */
205                                 /* SSRC, HSEC, RMB, SURF */
206                         }
207                         ptr += 26;
208                 }
209
210                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
211                         ptr[0] = SMS_GEOMETRY_PAGE;
212                         ptr[1] = 24;
213                         if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
214                                 uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
215                                 /* number of cylinders */
216                                 ptr[2] = (cyl >> 24) & 0xff;
217                                 ptr[3] = (cyl >> 16) & 0xff;
218                                 ptr[4] = cyl & 0xff;
219                                 /* number of heads */
220                                 ptr[5] = PSEUDO_HDS;
221                                 /* starting cylinder- write precompensation */
222                                 /* ptr[6] = 0; */
223                                 /* ptr[7] = 0; */
224                                 /* ptr[8] = 0; */
225                                 /* starting cylinder- reduced write current */
226                                 /* ptr[9] = 0; */
227                                 /* ptr[10] = 0; */
228                                 /* ptr[11] = 0; */
229                                 /* drive step rate */
230                                 /* ptr[12] = 0; */
231                                 /* ptr[13] = 0; */
232                                 /* landing zone cylinder */
233                                 /* ptr[14] = 0; */
234                                 /* ptr[15] = 0; */
235                                 /* ptr[16] = 0; */
236                                 /* RPL */
237                                 /* ptr[17] = 0; */
238                                 /* rotational offset */
239                                 /* ptr[18] = 0; */
240                                 /* medium rotation rate -  7200 RPM */
241                                 ptr[20] = 0x1c;
242                                 ptr[21] = 0x20;
243                         }
244                         ptr += 26;
245                 }
246
247                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
248                         ptr[0] = SMS_CACHE_PAGE;
249                         ptr[1] = 18;
250                         ptr[2] = 1 << 2;
251                         ptr += 20;
252                 }
253
254                 if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
255                         ptr[0] = SMS_CONTROL_MODE_PAGE;
256                         ptr[1] = 10;
257                         if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
258                                 ptr[3] = 1 << 4; /* unrestricted reordering allowed */
259                                 ptr[8] = 0x75;   /* 30000 ms */
260                                 ptr[9] = 0x30;
261                         }
262                         ptr += 12;
263                 }
264                 nbyte = (char *)ptr - &junk[0];
265                 ptr[0] = nbyte - 4;
266
267                 if (cdb[0] == MODE_SENSE) {
268                         data_len = min(cdb[4], csio->dxfer_len);
269                 } else {
270                         uint16_t tw = (cdb[7] << 8) | cdb[8];
271                         data_len = min(tw, csio->dxfer_len);
272                 }
273                 data_len = min(data_len, nbyte);
274                 if (data_len) {
275                         memcpy(csio->data_ptr, junk, data_len);
276                 }
277                 csio->resid = csio->dxfer_len - data_len;
278                 break;
279         }
280         case READ_6:
281         case READ_10:
282         case READ_12:
283         case READ_16:
284         case WRITE_6:
285         case WRITE_10:
286         case WRITE_12:
287         case WRITE_16:
288                 if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
289                         vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
290                         break;
291                 }
292                 if (data_len) {
293                         if ((cdb[0] & 0xf) == 8) {
294                                 memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
295                         } else {
296                                 memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
297                         }
298                         csio->resid = csio->dxfer_len - data_len;
299                 } else {
300                         csio->resid = csio->dxfer_len;
301                 }
302                 break;
303
304         case READ_CAPACITY:
305                 if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
306                         vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
307                         break;
308                 }
309                 if (cdb[8] & 0x1) { /* PMI */
310                         csio->data_ptr[0] = 0xff;
311                         csio->data_ptr[1] = 0xff;
312                         csio->data_ptr[2] = 0xff;
313                         csio->data_ptr[3] = 0xff;
314                 } else {
315                         uint64_t last_blk = DISK_NBLKS - 1;
316                         if (last_blk < 0xffffffffULL) {
317                             csio->data_ptr[0] = (last_blk >> 24) & 0xff;
318                             csio->data_ptr[1] = (last_blk >> 16) & 0xff;
319                             csio->data_ptr[2] = (last_blk >>  8) & 0xff;
320                             csio->data_ptr[3] = (last_blk) & 0xff;
321                         } else {
322                             csio->data_ptr[0] = 0xff;
323                             csio->data_ptr[1] = 0xff;
324                             csio->data_ptr[2] = 0xff;
325                             csio->data_ptr[3] = 0xff;
326                         }
327                 }
328                 csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
329                 csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
330                 csio->data_ptr[6] = ((1 << DISK_SHIFT) >>  8) & 0xff;
331                 csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
332                 break;
333         default:
334                 vhba_default_cmd(csio, MAX_LUN, NULL);
335                 break;
336         }
337         if (csio->scsi_status != SCSI_STATUS_OK) {
338                 camstatus = CAM_SCSI_STATUS_ERROR;
339                 if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
340                         camstatus |= CAM_AUTOSNS_VALID;
341                 }
342         } else {
343                 csio->scsi_status = SCSI_STATUS_OK;
344                 camstatus = CAM_REQ_CMP;
345         }
346         vhba_set_status(&csio->ccb_h, camstatus);
347         TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
348 }
349 DEV_MODULE(vhba_faulty, vhba_modprobe, NULL);