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