Line data Source code
1 : /*-
2 : * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 : * Copyright (c) 2012 NetApp Inc.
4 : * Copyright (c) 2012 Citrix Inc.
5 : * Copyright (c) 2017 Mike Belopuhov <mike@esdenera.com>
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice unmodified, this list of conditions, and the following
13 : * disclaimer.
14 : * 2. Redistributions in binary form must reproduce the above copyright
15 : * notice, this list of conditions and the following disclaimer in the
16 : * documentation and/or other materials provided with the distribution.
17 : *
18 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : */
29 :
30 : /*
31 : * The OpenBSD port was done under funding by Esdenera Networks GmbH.
32 : */
33 :
34 : /* #define HVS_DEBUG_IO */
35 :
36 : #include <sys/param.h>
37 : #include <sys/systm.h>
38 : #include <sys/atomic.h>
39 : #include <sys/device.h>
40 : #include <sys/kernel.h>
41 : #include <sys/buf.h>
42 : #include <sys/malloc.h>
43 : #include <sys/task.h>
44 :
45 : #include <machine/bus.h>
46 :
47 : #include <uvm/uvm_extern.h>
48 :
49 : #include <dev/pv/hypervreg.h>
50 : #include <dev/pv/hypervvar.h>
51 :
52 : #include <scsi/scsi_all.h>
53 : #include <scsi/cd.h>
54 : #include <scsi/scsi_disk.h>
55 : #include <scsi/scsiconf.h>
56 :
57 : #define HVS_PROTO_VERSION_WIN6 0x200
58 : #define HVS_PROTO_VERSION_WIN7 0x402
59 : #define HVS_PROTO_VERSION_WIN8 0x501
60 : #define HVS_PROTO_VERSION_WIN8_1 0x600
61 : #define HVS_PROTO_VERSION_WIN10 0x602
62 :
63 : #define HVS_MSG_IODONE 0x01
64 : #define HVS_MSG_DEVGONE 0x02
65 : #define HVS_MSG_ENUMERATE 0x0b
66 :
67 : #define HVS_REQ_SCSIIO 0x03
68 : #define HVS_REQ_STARTINIT 0x07
69 : #define HVS_REQ_FINISHINIT 0x08
70 : #define HVS_REQ_QUERYPROTO 0x09
71 : #define HVS_REQ_QUERYPROPS 0x0a
72 :
73 : struct hvs_cmd_hdr {
74 : uint32_t hdr_op;
75 : uint32_t hdr_flags;
76 : uint32_t hdr_status;
77 : #define cmd_op cmd_hdr.hdr_op
78 : #define cmd_flags cmd_hdr.hdr_flags
79 : #define cmd_status cmd_hdr.hdr_status
80 : } __packed;
81 :
82 : /* Negotiate version */
83 : struct hvs_cmd_ver {
84 : struct hvs_cmd_hdr cmd_hdr;
85 : uint16_t cmd_ver;
86 : uint16_t cmd_rev;
87 : } __packed;
88 :
89 : /* Query channel properties */
90 : struct hvs_chp {
91 : uint16_t chp_proto;
92 : uint8_t chp_path;
93 : uint8_t chp_target;
94 : uint16_t chp_maxchan;
95 : uint16_t chp_port;
96 : uint32_t chp_chflags;
97 : uint32_t chp_maxfer;
98 : uint64_t chp_chanid;
99 : } __packed;
100 :
101 : struct hvs_cmd_chp {
102 : struct hvs_cmd_hdr cmd_hdr;
103 : struct hvs_chp cmd_chp;
104 : } __packed;
105 :
106 : #define SENSE_DATA_LEN_WIN7 18
107 : #define SENSE_DATA_LEN 20
108 : #define MAX_SRB_DATA 20
109 :
110 : /* SCSI Request Block */
111 : struct hvs_srb {
112 : uint16_t srb_reqlen;
113 : uint8_t srb_iostatus;
114 : uint8_t srb_scsistatus;
115 :
116 : uint8_t srb_initiator;
117 : uint8_t srb_bus;
118 : uint8_t srb_target;
119 : uint8_t srb_lun;
120 :
121 : uint8_t srb_cdblen;
122 : uint8_t srb_senselen;
123 : uint8_t srb_direction;
124 : uint8_t _reserved;
125 :
126 : uint32_t srb_datalen;
127 : uint8_t srb_data[MAX_SRB_DATA];
128 : } __packed;
129 :
130 : #define SRB_DATA_WRITE 0
131 : #define SRB_DATA_READ 1
132 : #define SRB_DATA_NONE 2
133 :
134 : #define SRB_STATUS_PENDING 0x00
135 : #define SRB_STATUS_SUCCESS 0x01
136 : #define SRB_STATUS_ABORTED 0x02
137 : #define SRB_STATUS_ERROR 0x04
138 : #define SRB_STATUS_INVALID_LUN 0x20
139 : #define SRB_STATUS_QUEUE_FROZEN 0x40
140 : #define SRB_STATUS_AUTOSENSE_VALID 0x80
141 :
142 : #define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002
143 : #define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004
144 : #define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008
145 : #define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010
146 : #define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020
147 : #define SRB_FLAGS_DATA_IN 0x00000040
148 : #define SRB_FLAGS_DATA_OUT 0x00000080
149 : #define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000
150 : #define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100
151 : #define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200
152 : #define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400
153 :
154 : struct hvs_cmd_io {
155 : struct hvs_cmd_hdr cmd_hdr;
156 : struct hvs_srb cmd_srb;
157 : /* Win8 extensions */
158 : uint16_t _reserved;
159 : uint8_t cmd_qtag;
160 : uint8_t cmd_qaction;
161 : uint32_t cmd_srbflags;
162 : uint32_t cmd_timeout;
163 : uint32_t cmd_qsortkey;
164 : } __packed;
165 :
166 : #define HVS_CMD_SIZE 64
167 :
168 : union hvs_cmd {
169 : struct hvs_cmd_hdr cmd_hdr;
170 : struct hvs_cmd_ver ver;
171 : struct hvs_cmd_chp chp;
172 : struct hvs_cmd_io io;
173 : uint8_t pad[HVS_CMD_SIZE];
174 : } __packed;
175 :
176 : #define HVS_RING_SIZE (20 * PAGE_SIZE)
177 : #define HVS_MAX_CCB 128
178 : #define HVS_MAX_SGE (MAXPHYS / PAGE_SIZE + 1)
179 :
180 : struct hvs_softc;
181 :
182 : struct hvs_ccb {
183 : struct scsi_xfer *ccb_xfer; /* associated transfer */
184 : union hvs_cmd *ccb_cmd; /* associated command */
185 : union hvs_cmd ccb_rsp; /* response */
186 : bus_dmamap_t ccb_dmap; /* transfer map */
187 : uint64_t ccb_rid; /* request id */
188 : struct vmbus_gpa_range *ccb_sgl;
189 : int ccb_nsge;
190 : void (*ccb_done)(struct hvs_ccb *);
191 : void *ccb_cookie;
192 : SIMPLEQ_ENTRY(hvs_ccb) ccb_link;
193 : };
194 : SIMPLEQ_HEAD(hvs_ccb_queue, hvs_ccb);
195 :
196 : struct hvs_softc {
197 : struct device sc_dev;
198 : struct hv_softc *sc_hvsc;
199 : struct hv_channel *sc_chan;
200 : bus_dma_tag_t sc_dmat;
201 :
202 : int sc_proto;
203 : int sc_flags;
204 : #define HVSF_SCSI 0x0001
205 : #define HVSF_W8PLUS 0x0002
206 : struct hvs_chp sc_props;
207 :
208 : /* CCBs */
209 : int sc_nccb;
210 : struct hvs_ccb *sc_ccbs;
211 : struct hvs_ccb_queue sc_ccb_fq; /* free queue */
212 : struct mutex sc_ccb_fqlck;
213 :
214 : int sc_bus;
215 : int sc_initiator;
216 :
217 : struct scsi_iopool sc_iopool;
218 : struct scsi_adapter sc_switch;
219 : struct scsi_link sc_link;
220 : struct device *sc_scsibus;
221 : struct task sc_probetask;
222 : };
223 :
224 : int hvs_match(struct device *, void *, void *);
225 : void hvs_attach(struct device *, struct device *, void *);
226 :
227 : void hvs_scsi_cmd(struct scsi_xfer *);
228 : void hvs_scsi_cmd_done(struct hvs_ccb *);
229 : int hvs_start(struct hvs_softc *, struct hvs_ccb *);
230 : int hvs_poll(struct hvs_softc *, struct hvs_ccb *);
231 : void hvs_poll_done(struct hvs_ccb *);
232 : void hvs_intr(void *);
233 : void hvs_scsi_probe(void *arg);
234 : void hvs_scsi_done(struct scsi_xfer *, int);
235 :
236 : int hvs_connect(struct hvs_softc *);
237 : void hvs_empty_done(struct hvs_ccb *);
238 :
239 : int hvs_alloc_ccbs(struct hvs_softc *);
240 : void hvs_free_ccbs(struct hvs_softc *);
241 : void *hvs_get_ccb(void *);
242 : void hvs_put_ccb(void *, void *);
243 :
244 : struct cfdriver hvs_cd = {
245 : NULL, "hvs", DV_DULL
246 : };
247 :
248 : const struct cfattach hvs_ca = {
249 : sizeof(struct hvs_softc), hvs_match, hvs_attach
250 : };
251 :
252 : int
253 0 : hvs_match(struct device *parent, void *match, void *aux)
254 : {
255 0 : struct hv_attach_args *aa = aux;
256 :
257 0 : if (strcmp("ide", aa->aa_ident) &&
258 0 : strcmp("scsi", aa->aa_ident))
259 0 : return (0);
260 :
261 0 : return (1);
262 0 : }
263 :
264 : void
265 0 : hvs_attach(struct device *parent, struct device *self, void *aux)
266 : {
267 0 : struct hv_attach_args *aa = aux;
268 0 : struct hvs_softc *sc = (struct hvs_softc *)self;
269 0 : struct scsibus_attach_args saa;
270 : extern int pciide_skip_ata;
271 :
272 0 : sc->sc_hvsc = (struct hv_softc *)parent;
273 0 : sc->sc_chan = aa->aa_chan;
274 0 : sc->sc_dmat = aa->aa_dmat;
275 :
276 0 : printf(" channel %u: %s", sc->sc_chan->ch_id, aa->aa_ident);
277 :
278 0 : if (strcmp("scsi", aa->aa_ident) == 0)
279 0 : sc->sc_flags |= HVSF_SCSI;
280 :
281 0 : if (hv_channel_setdeferred(sc->sc_chan, sc->sc_dev.dv_xname)) {
282 0 : printf(": failed to create the interrupt thread\n");
283 0 : return;
284 : }
285 :
286 0 : if (hv_channel_open(sc->sc_chan, HVS_RING_SIZE, &sc->sc_props,
287 0 : sizeof(sc->sc_props), hvs_intr, sc)) {
288 0 : printf(": failed to open channel\n");
289 0 : return;
290 : }
291 :
292 0 : hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
293 :
294 0 : if (hvs_alloc_ccbs(sc))
295 0 : return;
296 :
297 0 : if (hvs_connect(sc))
298 0 : return;
299 :
300 0 : printf(", protocol %u.%u\n", (sc->sc_proto >> 8) & 0xff,
301 0 : sc->sc_proto & 0xff);
302 :
303 0 : if (sc->sc_proto >= HVS_PROTO_VERSION_WIN8)
304 0 : sc->sc_flags |= HVSF_W8PLUS;
305 :
306 0 : task_set(&sc->sc_probetask, hvs_scsi_probe, sc);
307 :
308 0 : sc->sc_switch.scsi_cmd = hvs_scsi_cmd;
309 0 : sc->sc_switch.scsi_minphys = scsi_minphys;
310 :
311 0 : sc->sc_link.adapter = &sc->sc_switch;
312 0 : sc->sc_link.adapter_softc = self;
313 0 : sc->sc_link.luns = sc->sc_flags & HVSF_SCSI ? 64 : 1;
314 0 : sc->sc_link.adapter_buswidth = 2;
315 0 : sc->sc_link.adapter_target = 2;
316 0 : sc->sc_link.openings = sc->sc_nccb;
317 0 : sc->sc_link.pool = &sc->sc_iopool;
318 :
319 0 : memset(&saa, 0, sizeof(saa));
320 0 : saa.saa_sc_link = &sc->sc_link;
321 0 : sc->sc_scsibus = config_found(self, &saa, scsiprint);
322 :
323 : /*
324 : * If the driver has successfully attached to an IDE
325 : * device, we need to make sure that the same disk is
326 : * not available to the system via pciide(4) causing
327 : * DUID conflicts and preventing system from booting.
328 : */
329 0 : if (!(sc->sc_flags & HVSF_SCSI) && sc->sc_scsibus)
330 0 : pciide_skip_ata = 1;
331 0 : }
332 :
333 : void
334 0 : hvs_scsi_cmd(struct scsi_xfer *xs)
335 : {
336 0 : struct scsi_link *link = xs->sc_link;
337 0 : struct hvs_softc *sc = link->adapter_softc;
338 0 : struct hvs_ccb *ccb = xs->io;
339 0 : union hvs_cmd cmd;
340 0 : struct hvs_cmd_io *io = &cmd.io;
341 0 : struct hvs_srb *srb = &io->cmd_srb;
342 : int i, rv, flags = BUS_DMA_NOWAIT;
343 :
344 0 : if (xs->cmdlen > MAX_SRB_DATA) {
345 0 : printf("%s: CDB is too big: %d\n", sc->sc_dev.dv_xname,
346 : xs->cmdlen);
347 0 : memset(&xs->sense, 0, sizeof(xs->sense));
348 0 : xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
349 0 : xs->sense.flags = SKEY_ILLEGAL_REQUEST;
350 0 : xs->sense.add_sense_code = 0x20;
351 0 : hvs_scsi_done(xs, XS_SENSE);
352 0 : return;
353 : }
354 :
355 0 : KERNEL_UNLOCK();
356 :
357 0 : memset(&cmd, 0, sizeof(cmd));
358 :
359 0 : srb->srb_initiator = sc->sc_initiator;
360 0 : srb->srb_bus = sc->sc_bus;
361 0 : srb->srb_target = link->target;
362 0 : srb->srb_lun = link->lun;
363 :
364 0 : srb->srb_cdblen = xs->cmdlen;
365 0 : memcpy(srb->srb_data, xs->cmd, xs->cmdlen);
366 :
367 0 : switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
368 : case SCSI_DATA_IN:
369 0 : srb->srb_direction = SRB_DATA_READ;
370 0 : if (sc->sc_flags & HVSF_W8PLUS)
371 0 : io->cmd_srbflags |= SRB_FLAGS_DATA_IN;
372 : flags |= BUS_DMA_WRITE;
373 0 : break;
374 : case SCSI_DATA_OUT:
375 0 : srb->srb_direction = SRB_DATA_WRITE;
376 0 : if (sc->sc_flags & HVSF_W8PLUS)
377 0 : io->cmd_srbflags |= SRB_FLAGS_DATA_OUT;
378 : flags |= BUS_DMA_READ;
379 0 : break;
380 : default:
381 0 : srb->srb_direction = SRB_DATA_NONE;
382 0 : if (sc->sc_flags & HVSF_W8PLUS)
383 0 : io->cmd_srbflags |= SRB_FLAGS_NO_DATA_TRANSFER;
384 : break;
385 : }
386 :
387 0 : srb->srb_datalen = xs->datalen;
388 :
389 0 : if (sc->sc_flags & HVSF_W8PLUS) {
390 0 : srb->srb_reqlen = sizeof(*io);
391 0 : srb->srb_senselen = SENSE_DATA_LEN;
392 0 : } else {
393 0 : srb->srb_reqlen = sizeof(struct hvs_cmd_hdr) +
394 : sizeof(struct hvs_srb);
395 0 : srb->srb_senselen = SENSE_DATA_LEN_WIN7;
396 : }
397 :
398 0 : cmd.cmd_op = HVS_REQ_SCSIIO;
399 0 : cmd.cmd_flags = VMBUS_CHANPKT_FLAG_RC;
400 :
401 0 : if (xs->datalen > 0) {
402 0 : rv = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmap, xs->data,
403 : xs->datalen, NULL, flags);
404 0 : if (rv) {
405 0 : printf("%s: failed to load %d bytes (%d)\n",
406 0 : sc->sc_dev.dv_xname, xs->datalen, rv);
407 0 : KERNEL_LOCK();
408 0 : hvs_scsi_done(xs, XS_DRIVER_STUFFUP);
409 0 : return;
410 : }
411 :
412 0 : ccb->ccb_sgl->gpa_len = xs->datalen;
413 0 : ccb->ccb_sgl->gpa_ofs = (vaddr_t)xs->data & PAGE_MASK;
414 0 : for (i = 0; i < ccb->ccb_dmap->dm_nsegs; i++)
415 0 : ccb->ccb_sgl->gpa_page[i] =
416 0 : atop(ccb->ccb_dmap->dm_segs[i].ds_addr);
417 0 : ccb->ccb_nsge = ccb->ccb_dmap->dm_nsegs;
418 0 : } else
419 0 : ccb->ccb_nsge = 0;
420 :
421 0 : ccb->ccb_xfer = xs;
422 0 : ccb->ccb_cmd = &cmd;
423 0 : ccb->ccb_done = hvs_scsi_cmd_done;
424 :
425 : #ifdef HVS_DEBUG_IO
426 : DPRINTF("%s: %u.%u: rid %llu opcode %#x flags %#x datalen %d\n",
427 : sc->sc_dev.dv_xname, link->target, link->lun, ccb->ccb_rid,
428 : xs->cmd->opcode, xs->flags, xs->datalen);
429 : #endif
430 :
431 0 : if (xs->flags & SCSI_POLL)
432 0 : rv = hvs_poll(sc, ccb);
433 : else
434 0 : rv = hvs_start(sc, ccb);
435 0 : if (rv) {
436 0 : KERNEL_LOCK();
437 0 : hvs_scsi_done(xs, XS_DRIVER_STUFFUP);
438 0 : return;
439 : }
440 :
441 0 : KERNEL_LOCK();
442 0 : }
443 :
444 : int
445 0 : hvs_start(struct hvs_softc *sc, struct hvs_ccb *ccb)
446 : {
447 0 : union hvs_cmd *cmd = ccb->ccb_cmd;
448 : int rv;
449 :
450 0 : ccb->ccb_cmd = NULL;
451 :
452 0 : if (ccb->ccb_nsge > 0) {
453 0 : rv = hv_channel_send_prpl(sc->sc_chan, ccb->ccb_sgl,
454 0 : ccb->ccb_nsge, cmd, HVS_CMD_SIZE, ccb->ccb_rid);
455 0 : if (rv) {
456 0 : printf("%s: failed to submit operation %x via prpl\n",
457 0 : sc->sc_dev.dv_xname, cmd->cmd_op);
458 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap);
459 0 : }
460 : } else {
461 0 : rv = hv_channel_send(sc->sc_chan, cmd, HVS_CMD_SIZE,
462 0 : ccb->ccb_rid, VMBUS_CHANPKT_TYPE_INBAND,
463 : VMBUS_CHANPKT_FLAG_RC);
464 0 : if (rv)
465 0 : printf("%s: failed to submit operation %x\n",
466 0 : sc->sc_dev.dv_xname, cmd->cmd_op);
467 : }
468 :
469 0 : return (rv);
470 : }
471 :
472 : void
473 0 : hvs_poll_done(struct hvs_ccb *ccb)
474 : {
475 0 : int *rv = ccb->ccb_cookie;
476 :
477 0 : if (ccb->ccb_cmd) {
478 0 : memcpy(&ccb->ccb_rsp, ccb->ccb_cmd, HVS_CMD_SIZE);
479 0 : ccb->ccb_cmd = &ccb->ccb_rsp;
480 0 : } else
481 0 : memset(&ccb->ccb_rsp, 0, HVS_CMD_SIZE);
482 :
483 0 : *rv = 0;
484 0 : }
485 :
486 : int
487 0 : hvs_poll(struct hvs_softc *sc, struct hvs_ccb *ccb)
488 : {
489 : void (*done)(struct hvs_ccb *);
490 : void *cookie;
491 0 : int s, rv = 1;
492 :
493 0 : done = ccb->ccb_done;
494 0 : cookie = ccb->ccb_cookie;
495 :
496 0 : ccb->ccb_done = hvs_poll_done;
497 0 : ccb->ccb_cookie = &rv;
498 :
499 0 : if (hvs_start(sc, ccb)) {
500 0 : ccb->ccb_cookie = cookie;
501 0 : ccb->ccb_done = done;
502 0 : return (-1);
503 : }
504 :
505 0 : while (rv == 1) {
506 0 : delay(10);
507 0 : s = splbio();
508 0 : hvs_intr(sc);
509 0 : splx(s);
510 : }
511 :
512 0 : ccb->ccb_cookie = cookie;
513 0 : ccb->ccb_done = done;
514 0 : ccb->ccb_done(ccb);
515 :
516 0 : return (0);
517 0 : }
518 :
519 : void
520 0 : hvs_intr(void *xsc)
521 : {
522 0 : struct hvs_softc *sc = xsc;
523 : struct hvs_ccb *ccb;
524 0 : union hvs_cmd cmd;
525 0 : uint64_t rid;
526 0 : uint32_t rlen;
527 : int rv;
528 :
529 0 : for (;;) {
530 0 : rv = hv_channel_recv(sc->sc_chan, &cmd, sizeof(cmd), &rlen,
531 : &rid, 0);
532 0 : switch (rv) {
533 : case 0:
534 : break;
535 : case EAGAIN:
536 : /* No more messages to process */
537 0 : return;
538 : default:
539 0 : printf("%s: error %d while receiving a reply\n",
540 0 : sc->sc_dev.dv_xname, rv);
541 0 : return;
542 : }
543 0 : if (rlen != sizeof(cmd)) {
544 0 : printf("%s: short read: %u\n", sc->sc_dev.dv_xname,
545 : rlen);
546 0 : return;
547 : }
548 :
549 : #ifdef HVS_DEBUG_IO
550 : DPRINTF("%s: rid %llu opertaion %u flags %#x status %#x\n",
551 : sc->sc_dev.dv_xname, rid, cmd.cmd_op, cmd.cmd_flags,
552 : cmd.cmd_status);
553 : #endif
554 :
555 0 : switch (cmd.cmd_op) {
556 : case HVS_MSG_IODONE:
557 0 : if (rid >= sc->sc_nccb) {
558 0 : printf("%s: invalid response %#llx\n",
559 0 : sc->sc_dev.dv_xname, rid);
560 0 : continue;
561 : }
562 0 : ccb = &sc->sc_ccbs[rid];
563 0 : ccb->ccb_cmd = &cmd;
564 0 : ccb->ccb_done(ccb);
565 0 : break;
566 : case HVS_MSG_ENUMERATE:
567 0 : task_add(systq, &sc->sc_probetask);
568 0 : break;
569 : default:
570 0 : printf("%s: operation %u is not implemented\n",
571 0 : sc->sc_dev.dv_xname, cmd.cmd_op);
572 0 : }
573 : }
574 0 : }
575 :
576 : static inline int
577 0 : is_inquiry_valid(struct scsi_inquiry_data *inq)
578 : {
579 0 : if ((inq->device & SID_TYPE) == T_NODEVICE)
580 0 : return (0);
581 0 : if ((inq->device & SID_QUAL) == SID_QUAL_BAD_LU)
582 0 : return (0);
583 0 : return (1);
584 0 : }
585 :
586 : static inline void
587 0 : fixup_inquiry(struct scsi_xfer *xs, struct hvs_srb *srb)
588 : {
589 0 : struct hvs_softc *sc = xs->sc_link->adapter_softc;
590 0 : struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)xs->data;
591 : int datalen, resplen;
592 0 : char vendor[8];
593 :
594 0 : resplen = srb->srb_datalen >= 5 ? inq->additional_length + 5 : 0;
595 0 : datalen = MIN(resplen, srb->srb_datalen);
596 :
597 : /* Fixup wrong response from WS2012 */
598 0 : if ((sc->sc_proto == HVS_PROTO_VERSION_WIN8_1 ||
599 0 : sc->sc_proto == HVS_PROTO_VERSION_WIN8 ||
600 0 : sc->sc_proto == HVS_PROTO_VERSION_WIN7) &&
601 0 : !is_inquiry_valid(inq) && datalen >= 4 &&
602 0 : (inq->version == 0 || inq->response_format == 0)) {
603 0 : inq->version = 0x05; /* SPC-3 */
604 0 : inq->response_format = 2;
605 0 : } else if (datalen >= SID_INQUIRY_HDR + SID_SCSI2_ALEN) {
606 : /*
607 : * Upgrade SPC2 to SPC3 if host is Win8 or WS2012 R2
608 : * to support UNMAP feature.
609 : */
610 0 : scsi_strvis(vendor, inq->vendor, sizeof(vendor));
611 0 : if ((sc->sc_proto == HVS_PROTO_VERSION_WIN8_1 ||
612 0 : sc->sc_proto == HVS_PROTO_VERSION_WIN8) &&
613 0 : SCSISPC(inq->version) == 2 &&
614 0 : !strncmp(vendor, "Msft", 4))
615 0 : inq->version = 0x05; /* SPC-3 */
616 : }
617 0 : }
618 :
619 : void
620 0 : hvs_scsi_cmd_done(struct hvs_ccb *ccb)
621 : {
622 0 : struct scsi_xfer *xs = ccb->ccb_xfer;
623 0 : struct hvs_softc *sc = xs->sc_link->adapter_softc;
624 0 : union hvs_cmd *cmd = ccb->ccb_cmd;
625 : struct hvs_srb *srb;
626 : bus_dmamap_t map;
627 : int error;
628 :
629 0 : map = ccb->ccb_dmap;
630 0 : bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
631 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
632 0 : bus_dmamap_unload(sc->sc_dmat, map);
633 :
634 0 : xs = ccb->ccb_xfer;
635 0 : srb = &cmd->io.cmd_srb;
636 :
637 0 : xs->status = srb->srb_scsistatus & 0xff;
638 :
639 0 : switch (xs->status) {
640 : case SCSI_OK:
641 0 : if ((srb->srb_iostatus & ~(SRB_STATUS_AUTOSENSE_VALID |
642 0 : SRB_STATUS_QUEUE_FROZEN)) != SRB_STATUS_SUCCESS)
643 0 : error = XS_SELTIMEOUT;
644 : else
645 : error = XS_NOERROR;
646 : break;
647 : case SCSI_BUSY:
648 : case SCSI_QUEUE_FULL:
649 0 : printf("%s: status %#x iostatus %#x (busy)\n",
650 0 : sc->sc_dev.dv_xname, srb->srb_scsistatus,
651 0 : srb->srb_iostatus);
652 : error = XS_BUSY;
653 0 : break;
654 : case SCSI_CHECK:
655 0 : if (srb->srb_iostatus & SRB_STATUS_AUTOSENSE_VALID) {
656 0 : memcpy(&xs->sense, srb->srb_data,
657 : MIN(sizeof(xs->sense), srb->srb_senselen));
658 : error = XS_SENSE;
659 0 : break;
660 : }
661 : /* FALLTHROUGH */
662 : default:
663 : error = XS_DRIVER_STUFFUP;
664 0 : }
665 :
666 0 : if (error == XS_NOERROR) {
667 0 : if (xs->cmd->opcode == INQUIRY)
668 0 : fixup_inquiry(xs, srb);
669 0 : else if (srb->srb_direction != SRB_DATA_NONE)
670 0 : xs->resid = xs->datalen - srb->srb_datalen;
671 : }
672 :
673 0 : KERNEL_LOCK();
674 0 : hvs_scsi_done(xs, error);
675 0 : KERNEL_UNLOCK();
676 0 : }
677 :
678 : void
679 0 : hvs_scsi_probe(void *arg)
680 : {
681 0 : struct hvs_softc *sc = arg;
682 :
683 0 : if (sc->sc_scsibus)
684 0 : scsi_probe_bus((void *)sc->sc_scsibus);
685 0 : }
686 :
687 : void
688 0 : hvs_scsi_done(struct scsi_xfer *xs, int error)
689 : {
690 : int s;
691 :
692 0 : KERNEL_ASSERT_LOCKED();
693 :
694 0 : xs->error = error;
695 :
696 0 : s = splbio();
697 0 : scsi_done(xs);
698 0 : splx(s);
699 0 : }
700 :
701 : int
702 0 : hvs_connect(struct hvs_softc *sc)
703 : {
704 : const uint32_t protos[] = {
705 : HVS_PROTO_VERSION_WIN10,
706 : HVS_PROTO_VERSION_WIN8_1,
707 : HVS_PROTO_VERSION_WIN8,
708 : HVS_PROTO_VERSION_WIN7,
709 : HVS_PROTO_VERSION_WIN6
710 : };
711 0 : union hvs_cmd ucmd;
712 : struct hvs_cmd_ver *cmd;
713 : struct hvs_chp *chp;
714 : struct hvs_ccb *ccb;
715 : int i;
716 :
717 0 : ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
718 0 : if (ccb == NULL) {
719 0 : printf(": failed to allocate ccb\n");
720 0 : return (-1);
721 : }
722 :
723 0 : ccb->ccb_done = hvs_empty_done;
724 :
725 0 : cmd = (struct hvs_cmd_ver *)&ucmd;
726 :
727 : /*
728 : * Begin initialization
729 : */
730 :
731 0 : memset(&ucmd, 0, sizeof(ucmd));
732 :
733 0 : cmd->cmd_op = HVS_REQ_STARTINIT;
734 0 : cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
735 :
736 0 : ccb->ccb_cmd = &ucmd;
737 0 : if (hvs_poll(sc, ccb)) {
738 0 : printf(": failed to send initialization command\n");
739 0 : scsi_io_put(&sc->sc_iopool, ccb);
740 0 : return (-1);
741 : }
742 0 : if (ccb->ccb_rsp.cmd_status != 0) {
743 0 : printf(": failed to initialize, status %#x\n",
744 : ccb->ccb_rsp.cmd_status);
745 0 : scsi_io_put(&sc->sc_iopool, ccb);
746 0 : return (-1);
747 : }
748 :
749 : /*
750 : * Negotiate protocol version
751 : */
752 :
753 0 : memset(&ucmd, 0, sizeof(ucmd));
754 :
755 0 : cmd->cmd_op = HVS_REQ_QUERYPROTO;
756 0 : cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
757 :
758 0 : for (i = 0; i < nitems(protos); i++) {
759 0 : cmd->cmd_ver = protos[i];
760 :
761 0 : ccb->ccb_cmd = &ucmd;
762 0 : if (hvs_poll(sc, ccb)) {
763 0 : printf(": failed to send protocol query\n");
764 0 : scsi_io_put(&sc->sc_iopool, ccb);
765 0 : return (-1);
766 : }
767 0 : if (ccb->ccb_rsp.cmd_status == 0) {
768 0 : sc->sc_proto = protos[i];
769 0 : break;
770 : }
771 : }
772 0 : if (!sc->sc_proto) {
773 0 : printf(": failed to negotiate protocol version\n");
774 0 : scsi_io_put(&sc->sc_iopool, ccb);
775 0 : return (-1);
776 : }
777 :
778 : /*
779 : * Query channel properties
780 : */
781 :
782 0 : memset(&ucmd, 0, sizeof(ucmd));
783 :
784 0 : cmd->cmd_op = HVS_REQ_QUERYPROPS;
785 0 : cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
786 :
787 0 : ccb->ccb_cmd = &ucmd;
788 0 : if (hvs_poll(sc, ccb)) {
789 0 : printf(": failed to send channel properties query\n");
790 0 : scsi_io_put(&sc->sc_iopool, ccb);
791 0 : return (-1);
792 : }
793 0 : if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE ||
794 0 : ccb->ccb_rsp.cmd_status != 0) {
795 0 : printf(": failed to obtain channel properties, status %#x\n",
796 0 : ccb->ccb_rsp.cmd_status);
797 0 : scsi_io_put(&sc->sc_iopool, ccb);
798 0 : return (-1);
799 : }
800 0 : chp = &ccb->ccb_rsp.chp.cmd_chp;
801 :
802 : DPRINTF(": proto %#x path %u target %u maxchan %u",
803 : chp->chp_proto, chp->chp_path, chp->chp_target,
804 : chp->chp_maxchan);
805 : DPRINTF(" port %u chflags %#x maxfer %u chanid %#llx",
806 : chp->chp_port, chp->chp_chflags, chp->chp_maxfer,
807 : chp->chp_chanid);
808 :
809 : /* XXX */
810 0 : sc->sc_bus = chp->chp_path;
811 0 : sc->sc_initiator = chp->chp_target;
812 :
813 : /*
814 : * Finish initialization
815 : */
816 :
817 0 : memset(&ucmd, 0, sizeof(ucmd));
818 :
819 0 : cmd->cmd_op = HVS_REQ_FINISHINIT;
820 0 : cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
821 :
822 0 : ccb->ccb_cmd = &ucmd;
823 0 : if (hvs_poll(sc, ccb)) {
824 0 : printf(": failed to send initialization finish\n");
825 0 : scsi_io_put(&sc->sc_iopool, ccb);
826 0 : return (-1);
827 : }
828 0 : if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE ||
829 0 : ccb->ccb_rsp.cmd_status != 0) {
830 0 : printf(": failed to finish initialization, status %#x\n",
831 0 : ccb->ccb_rsp.cmd_status);
832 0 : scsi_io_put(&sc->sc_iopool, ccb);
833 0 : return (-1);
834 : }
835 :
836 0 : scsi_io_put(&sc->sc_iopool, ccb);
837 :
838 0 : return (0);
839 0 : }
840 :
841 : void
842 0 : hvs_empty_done(struct hvs_ccb *ccb)
843 : {
844 : /* nothing */
845 0 : }
846 :
847 : int
848 0 : hvs_alloc_ccbs(struct hvs_softc *sc)
849 : {
850 : int i, error;
851 :
852 0 : SIMPLEQ_INIT(&sc->sc_ccb_fq);
853 0 : mtx_init(&sc->sc_ccb_fqlck, IPL_BIO);
854 :
855 0 : sc->sc_nccb = HVS_MAX_CCB;
856 :
857 0 : sc->sc_ccbs = mallocarray(sc->sc_nccb, sizeof(struct hvs_ccb),
858 : M_DEVBUF, M_ZERO | M_NOWAIT);
859 0 : if (sc->sc_ccbs == NULL) {
860 0 : printf(": failed to allocate CCBs\n");
861 0 : return (-1);
862 : }
863 :
864 0 : for (i = 0; i < sc->sc_nccb; i++) {
865 0 : error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, HVS_MAX_SGE,
866 : PAGE_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT,
867 : &sc->sc_ccbs[i].ccb_dmap);
868 0 : if (error) {
869 0 : printf(": failed to create a CCB memory map (%d)\n",
870 : error);
871 0 : goto errout;
872 : }
873 :
874 0 : sc->sc_ccbs[i].ccb_sgl = malloc(sizeof(struct vmbus_gpa_range) *
875 : (HVS_MAX_SGE + 1), M_DEVBUF, M_ZERO | M_NOWAIT);
876 0 : if (sc->sc_ccbs[i].ccb_sgl == NULL) {
877 0 : printf(": failed to allocate SGL array\n");
878 0 : goto errout;
879 : }
880 :
881 0 : sc->sc_ccbs[i].ccb_rid = i;
882 0 : hvs_put_ccb(sc, &sc->sc_ccbs[i]);
883 : }
884 :
885 0 : scsi_iopool_init(&sc->sc_iopool, sc, hvs_get_ccb, hvs_put_ccb);
886 :
887 0 : return (0);
888 :
889 : errout:
890 0 : hvs_free_ccbs(sc);
891 0 : return (-1);
892 0 : }
893 :
894 : void
895 0 : hvs_free_ccbs(struct hvs_softc *sc)
896 : {
897 : struct hvs_ccb *ccb;
898 : int i;
899 :
900 0 : for (i = 0; i < sc->sc_nccb; i++) {
901 0 : ccb = &sc->sc_ccbs[i];
902 0 : if (ccb->ccb_dmap == NULL)
903 : continue;
904 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 0, 0,
905 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
906 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap);
907 0 : bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmap);
908 :
909 0 : free(ccb->ccb_sgl, M_DEVBUF, sizeof(struct vmbus_gpa_range) *
910 : (HVS_MAX_SGE + 1));
911 0 : }
912 :
913 0 : free(sc->sc_ccbs, M_DEVBUF, sc->sc_nccb * sizeof(struct hvs_ccb));
914 0 : sc->sc_ccbs = NULL;
915 0 : sc->sc_nccb = 0;
916 0 : }
917 :
918 : void *
919 0 : hvs_get_ccb(void *xsc)
920 : {
921 0 : struct hvs_softc *sc = xsc;
922 : struct hvs_ccb *ccb;
923 :
924 0 : mtx_enter(&sc->sc_ccb_fqlck);
925 0 : ccb = SIMPLEQ_FIRST(&sc->sc_ccb_fq);
926 0 : if (ccb != NULL)
927 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_fq, ccb_link);
928 0 : mtx_leave(&sc->sc_ccb_fqlck);
929 :
930 0 : return (ccb);
931 : }
932 :
933 : void
934 0 : hvs_put_ccb(void *xsc, void *io)
935 : {
936 0 : struct hvs_softc *sc = xsc;
937 0 : struct hvs_ccb *ccb = io;
938 :
939 0 : ccb->ccb_cmd = NULL;
940 0 : ccb->ccb_xfer = NULL;
941 0 : ccb->ccb_done = NULL;
942 0 : ccb->ccb_cookie = NULL;
943 0 : ccb->ccb_nsge = 0;
944 :
945 0 : mtx_enter(&sc->sc_ccb_fqlck);
946 0 : SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_fq, ccb, ccb_link);
947 0 : mtx_leave(&sc->sc_ccb_fqlck);
948 0 : }
|