2 * Copyright 2013 Nathan Whitehorn
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, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
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
18 * FOR 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/selinfo.h>
38 #include <sys/eventhandler.h>
40 #include <sys/bus_dma.h>
42 #include <sys/ioccom.h>
45 #include <sys/signalvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/endian.h>
51 #include <cam/cam_ccb.h>
52 #include <cam/cam_debug.h>
53 #include <cam/cam_periph.h>
54 #include <cam/cam_sim.h>
55 #include <cam/cam_xpt_periph.h>
56 #include <cam/cam_xpt_sim.h>
57 #include <cam/scsi/scsi_all.h>
58 #include <cam/scsi/scsi_message.h>
60 #include <dev/ofw/openfirm.h>
61 #include <dev/ofw/ofw_bus.h>
62 #include <dev/ofw/ofw_bus_subr.h>
64 #include <machine/bus.h>
65 #include <machine/resource.h>
67 #include <powerpc/pseries/phyp-hvcall.h>
71 /* VSCSI CRQ format from table 260 of PAPR spec 2.4 (page 760) */
83 TAILQ_ENTRY(vscsi_xfer) queue;
84 struct vscsi_softc *sc;
89 vmem_addr_t srp_iu_offset;
90 vmem_size_t srp_iu_size;
93 TAILQ_HEAD(vscsi_xferq, vscsi_xfer);
97 struct cam_devq *devq;
99 struct cam_path *path;
105 int max_transactions;
108 struct resource *irq;
111 bus_dma_tag_t crq_tag;
112 struct vscsi_crq *crq_queue;
114 bus_dmamap_t crq_map;
117 vmem_t *srp_iu_arena;
119 bus_addr_t srp_iu_phys;
121 bus_dma_tag_t data_tag;
123 struct vscsi_xfer loginxp;
124 struct vscsi_xfer *xfer;
125 struct vscsi_xferq active_xferq;
126 struct vscsi_xferq free_xferq;
133 uint64_t max_cmd_length;
135 uint16_t buffer_formats;
137 uint8_t reserved3[5];
138 uint8_t initiator_port_id[16];
139 uint8_t target_port_id[16];
142 struct srp_login_rsp {
145 uint32_t request_limit_delta;
147 uint32_t max_i_to_t_len;
148 uint32_t max_t_to_i_len;
149 uint16_t buffer_formats;
151 /* Some reserved bits follow */
159 uint8_t out_buffer_count;
160 uint8_t in_buffer_count;
164 uint8_t reserved3[3];
165 uint8_t additional_cdb;
167 uint8_t data_payload[0];
173 uint32_t request_limit_delta;
178 uint32_t data_out_resid;
179 uint32_t data_in_resid;
180 uint32_t sense_data_len;
181 uint32_t response_data_len;
182 uint8_t data_payload[0];
185 struct srp_tsk_mgmt {
191 uint8_t reserved3[2];
198 /* Message code type */
199 #define SRP_LOGIN_REQ 0x00
200 #define SRP_TSK_MGMT 0x01
202 #define SRP_I_LOGOUT 0x03
204 #define SRP_LOGIN_RSP 0xC0
206 #define SRP_LOGIN_REJ 0xC2
208 #define SRP_T_LOGOUT 0x80
209 #define SRP_CRED_REQ 0x81
210 #define SRP_AER_REQ 0x82
212 #define SRP_CRED_RSP 0x41
213 #define SRP_AER_RSP 0x41
215 /* Flags for srp_rsp flags field */
216 #define SRP_RSPVALID 0x01
217 #define SRP_SNSVALID 0x02
218 #define SRP_DOOVER 0x04
219 #define SRP_DOUNDER 0x08
220 #define SRP_DIOVER 0x10
221 #define SRP_DIUNDER 0x20
223 #define MAD_SUCESS 0x00
224 #define MAD_NOT_SUPPORTED 0xf1
225 #define MAD_FAILED 0xf7
227 #define MAD_EMPTY_IU 0x01
228 #define MAD_ERROR_LOGGING_REQUEST 0x02
229 #define MAD_ADAPTER_INFO_REQUEST 0x03
230 #define MAD_CAPABILITIES_EXCHANGE 0x05
231 #define MAD_PHYS_ADAP_INFO_REQUEST 0x06
232 #define MAD_TAPE_PASSTHROUGH_REQUEST 0x07
233 #define MAD_ENABLE_FAST_FAIL 0x08
235 static int vscsi_probe(device_t);
236 static int vscsi_attach(device_t);
237 static int vscsi_detach(device_t);
238 static void vscsi_cam_action(struct cam_sim *, union ccb *);
239 static void vscsi_cam_poll(struct cam_sim *);
240 static void vscsi_intr(void *arg);
241 static void vscsi_check_response_queue(struct vscsi_softc *sc);
242 static void vscsi_setup_bus(struct vscsi_softc *sc);
244 static void vscsi_srp_login(struct vscsi_softc *sc);
245 static void vscsi_crq_load_cb(void *, bus_dma_segment_t *, int, int);
246 static void vscsi_scsi_command(void *xxp, bus_dma_segment_t *segs,
248 static void vscsi_task_management(struct vscsi_softc *sc, union ccb *ccb);
249 static void vscsi_srp_response(struct vscsi_xfer *, struct vscsi_crq *);
251 static devclass_t vscsi_devclass;
252 static device_method_t vscsi_methods[] = {
253 DEVMETHOD(device_probe, vscsi_probe),
254 DEVMETHOD(device_attach, vscsi_attach),
255 DEVMETHOD(device_detach, vscsi_detach),
259 static driver_t vscsi_driver = {
262 sizeof(struct vscsi_softc)
264 DRIVER_MODULE(vscsi, vdevice, vscsi_driver, vscsi_devclass, 0, 0);
265 MALLOC_DEFINE(M_VSCSI, "vscsi", "CAM device queue for VSCSI");
268 vscsi_probe(device_t dev)
271 if (!ofw_bus_is_compatible(dev, "IBM,v-scsi"))
274 device_set_desc(dev, "POWER Hypervisor Virtual SCSI Bus");
279 vscsi_attach(device_t dev)
281 struct vscsi_softc *sc;
282 struct vscsi_xfer *xp;
285 sc = device_get_softc(dev);
290 mtx_init(&sc->io_lock, "vscsi", NULL, MTX_DEF);
293 OF_getencprop(ofw_bus_get_node(dev), "reg", &sc->unit,
296 /* Setup interrupt */
298 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
302 device_printf(dev, "Could not allocate IRQ\n");
303 mtx_destroy(&sc->io_lock);
307 bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_MPSAFE |
308 INTR_ENTROPY, NULL, vscsi_intr, sc, &sc->irq_cookie);
311 error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
312 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE,
313 256, BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex, &sc->io_lock,
316 TAILQ_INIT(&sc->active_xferq);
317 TAILQ_INIT(&sc->free_xferq);
319 /* First XFER for login data */
321 bus_dmamap_create(sc->data_tag, 0, &sc->loginxp.dmamap);
322 TAILQ_INSERT_TAIL(&sc->free_xferq, &sc->loginxp, queue);
325 error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
326 BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 8*PAGE_SIZE,
327 1, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &sc->crq_tag);
328 error = bus_dmamem_alloc(sc->crq_tag, (void **)&sc->crq_queue,
329 BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->crq_map);
332 error = bus_dmamap_load(sc->crq_tag, sc->crq_map, sc->crq_queue,
333 8*PAGE_SIZE, vscsi_crq_load_cb, sc, 0);
335 mtx_lock(&sc->io_lock);
337 sc->xfer = malloc(sizeof(sc->xfer[0])*sc->max_transactions, M_VSCSI,
339 for (i = 0; i < sc->max_transactions; i++) {
343 error = bus_dmamap_create(sc->data_tag, 0, &xp->dmamap);
345 device_printf(dev, "Could not create DMA map (%d)\n",
350 TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue);
352 mtx_unlock(&sc->io_lock);
354 /* Allocate CAM bits */
355 if ((sc->devq = cam_simq_alloc(sc->max_transactions)) == NULL)
358 sc->sim = cam_sim_alloc(vscsi_cam_action, vscsi_cam_poll, "vscsi", sc,
359 device_get_unit(dev), &sc->io_lock,
360 sc->max_transactions, sc->max_transactions,
362 if (sc->sim == NULL) {
363 cam_simq_free(sc->devq);
365 device_printf(dev, "CAM SIM attach failed\n");
370 mtx_lock(&sc->io_lock);
371 if (xpt_bus_register(sc->sim, dev, 0) != 0) {
372 device_printf(dev, "XPT bus registration failed\n");
373 cam_sim_free(sc->sim, FALSE);
375 cam_simq_free(sc->devq);
377 mtx_unlock(&sc->io_lock);
380 mtx_unlock(&sc->io_lock);
386 vscsi_detach(device_t dev)
388 struct vscsi_softc *sc;
390 sc = device_get_softc(dev);
394 if (sc->sim != NULL) {
395 mtx_lock(&sc->io_lock);
396 xpt_bus_deregister(cam_sim_path(sc->sim));
397 cam_sim_free(sc->sim, FALSE);
399 mtx_unlock(&sc->io_lock);
402 if (sc->devq != NULL) {
403 cam_simq_free(sc->devq);
407 mtx_destroy(&sc->io_lock);
413 vscsi_cam_action(struct cam_sim *sim, union ccb *ccb)
415 struct vscsi_softc *sc = cam_sim_softc(sim);
417 mtx_assert(&sc->io_lock, MA_OWNED);
419 switch (ccb->ccb_h.func_code) {
422 struct ccb_pathinq *cpi = &ccb->cpi;
424 cpi->version_num = 1;
425 cpi->hba_inquiry = PI_TAG_ABLE;
426 cpi->hba_misc = PIM_EXTLUNS;
427 cpi->target_sprt = 0;
428 cpi->hba_eng_cnt = 0;
431 cpi->initiator_id = ~0;
432 strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
433 strlcpy(cpi->hba_vid, "IBM", HBA_IDLEN);
434 strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
435 cpi->unit_number = cam_sim_unit(sim);
436 cpi->bus_id = cam_sim_bus(sim);
437 cpi->base_transfer_speed = 150000;
438 cpi->transport = XPORT_SRP;
439 cpi->transport_version = 0;
440 cpi->protocol = PROTO_SCSI;
441 cpi->protocol_version = SCSI_REV_SPC4;
442 cpi->ccb_h.status = CAM_REQ_CMP;
446 ccb->ccb_h.status = CAM_REQ_CMP;
449 ccb->ccb_h.status = CAM_REQ_INPROG;
450 vscsi_task_management(sc, ccb);
452 case XPT_GET_TRAN_SETTINGS:
453 ccb->cts.protocol = PROTO_SCSI;
454 ccb->cts.protocol_version = SCSI_REV_SPC4;
455 ccb->cts.transport = XPORT_SRP;
456 ccb->cts.transport_version = 0;
457 ccb->cts.proto_specific.valid = 0;
458 ccb->cts.xport_specific.valid = 0;
459 ccb->ccb_h.status = CAM_REQ_CMP;
461 case XPT_SET_TRAN_SETTINGS:
462 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
466 struct vscsi_xfer *xp;
468 ccb->ccb_h.status = CAM_REQ_INPROG;
470 xp = TAILQ_FIRST(&sc->free_xferq);
472 panic("SCSI queue flooded");
474 TAILQ_REMOVE(&sc->free_xferq, xp, queue);
475 TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
476 bus_dmamap_load_ccb(sc->data_tag, xp->dmamap,
477 ccb, vscsi_scsi_command, xp, 0);
482 ccb->ccb_h.status = CAM_REQ_INVALID;
491 vscsi_srp_login(struct vscsi_softc *sc)
493 struct vscsi_xfer *xp;
494 struct srp_login *login;
495 struct vscsi_crq crq;
498 mtx_assert(&sc->io_lock, MA_OWNED);
500 xp = TAILQ_FIRST(&sc->free_xferq);
502 panic("SCSI queue flooded");
504 TAILQ_REMOVE(&sc->free_xferq, xp, queue);
505 TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
508 xp->srp_iu_size = crq.iu_length = 64;
509 err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
510 M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
512 panic("Error during VMEM allocation (%d)", err);
514 login = (struct srp_login *)((uint8_t *)xp->sc->srp_iu_queue +
515 (uintptr_t)xp->srp_iu_offset);
516 bzero(login, xp->srp_iu_size);
517 login->type = SRP_LOGIN_REQ;
518 login->tag = (uint64_t)(xp);
519 login->max_cmd_length = htobe64(256);
520 login->buffer_formats = htobe16(0x1 | 0x2); /* Direct and indirect */
523 /* Create CRQ entry */
526 crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset;
527 bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
529 err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0],
530 ((uint64_t *)(&crq))[1]);
532 panic("CRQ send failure (%d)", err);
536 vscsi_task_management(struct vscsi_softc *sc, union ccb *ccb)
538 struct srp_tsk_mgmt *cmd;
539 struct vscsi_xfer *xp;
540 struct vscsi_crq crq;
543 mtx_assert(&sc->io_lock, MA_OWNED);
545 xp = TAILQ_FIRST(&sc->free_xferq);
547 panic("SCSI queue flooded");
549 TAILQ_REMOVE(&sc->free_xferq, xp, queue);
550 TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
552 xp->srp_iu_size = crq.iu_length = sizeof(*cmd);
553 err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
554 M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
556 panic("Error during VMEM allocation (%d)", err);
558 cmd = (struct srp_tsk_mgmt *)((uint8_t *)xp->sc->srp_iu_queue +
559 (uintptr_t)xp->srp_iu_offset);
560 bzero(cmd, xp->srp_iu_size);
561 cmd->type = SRP_TSK_MGMT;
562 cmd->tag = (uint64_t)xp;
563 cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
565 switch (ccb->ccb_h.func_code) {
567 cmd->function = 0x08;
570 panic("Unimplemented code %d", ccb->ccb_h.func_code);
574 bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE);
576 /* Create CRQ entry */
579 crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset;
581 err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0],
582 ((uint64_t *)(&crq))[1]);
584 panic("CRQ send failure (%d)", err);
588 vscsi_scsi_command(void *xxp, bus_dma_segment_t *segs, int nsegs, int err)
590 struct vscsi_xfer *xp = xxp;
592 union ccb *ccb = xp->ccb;
597 struct vscsi_crq crq;
599 KASSERT(err == 0, ("DMA error %d\n", err));
601 mtx_assert(&xp->sc->io_lock, MA_OWNED);
603 cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
604 ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes;
606 /* Command format from Table 20, page 37 of SRP spec */
607 crq.iu_length = 48 + ((nsegs > 1) ? 20 : 16) +
608 ((ccb->csio.cdb_len > 16) ? (ccb->csio.cdb_len - 16) : 0);
609 xp->srp_iu_size = crq.iu_length;
611 xp->srp_iu_size += nsegs*16;
612 xp->srp_iu_size = roundup(xp->srp_iu_size, 16);
613 err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
614 M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
616 panic("Error during VMEM allocation (%d)", err);
618 cmd = (struct srp_cmd *)((uint8_t *)xp->sc->srp_iu_queue +
619 (uintptr_t)xp->srp_iu_offset);
620 bzero(cmd, xp->srp_iu_size);
622 if (ccb->csio.cdb_len > 16)
623 cmd->additional_cdb = (ccb->csio.cdb_len - 16) << 2;
624 memcpy(cmd->cdb, cdb, ccb->csio.cdb_len);
626 cmd->tag = (uint64_t)(xp); /* Let the responder find this again */
627 cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
630 /* Use indirect descriptors */
631 switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
633 cmd->formats = (2 << 4);
639 panic("Does not support bidirectional commands (%d)",
640 ccb->ccb_h.flags & CAM_DIR_MASK);
644 desc_start = ((ccb->csio.cdb_len > 16) ?
645 ccb->csio.cdb_len - 16 : 0);
646 chunk_addr = xp->sc->srp_iu_phys + xp->srp_iu_offset + 20 +
647 desc_start + sizeof(*cmd);
648 chunk_size = 16*nsegs;
649 memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8);
650 memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4);
652 for (i = 0; i < nsegs; i++)
653 chunk_size += segs[i].ds_len;
654 memcpy(&cmd->data_payload[desc_start+16], &chunk_size, 4);
656 for (i = 0; i < nsegs; i++) {
657 chunk_addr = segs[i].ds_addr;
658 chunk_size = segs[i].ds_len;
660 memcpy(&cmd->data_payload[desc_start + 16*i],
662 /* Set handle tag to 0 */
663 memcpy(&cmd->data_payload[desc_start + 16*i + 12],
666 } else if (nsegs == 1) {
667 switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
669 cmd->formats = (1 << 4);
675 panic("Does not support bidirectional commands (%d)",
676 ccb->ccb_h.flags & CAM_DIR_MASK);
687 chunk_addr = segs[0].ds_addr;
688 chunk_size = segs[0].ds_len;
689 desc_start = ((ccb->csio.cdb_len > 16) ?
690 ccb->csio.cdb_len - 16 : 0);
692 memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8);
693 /* Set handle tag to 0 */
694 memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4);
695 KASSERT(xp->srp_iu_size >= 48 + ((ccb->csio.cdb_len > 16) ?
696 ccb->csio.cdb_len : 16), ("SRP IU command length"));
700 bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE);
702 /* Create CRQ entry */
705 crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset;
707 err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0],
708 ((uint64_t *)(&crq))[1]);
710 panic("CRQ send failure (%d)", err);
714 vscsi_crq_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err)
716 struct vscsi_softc *sc = xsc;
718 sc->crq_phys = segs[0].ds_addr;
719 sc->n_crqs = PAGE_SIZE/sizeof(struct vscsi_crq);
721 sc->srp_iu_queue = (uint8_t *)(sc->crq_queue);
722 sc->srp_iu_phys = segs[0].ds_addr;
723 sc->srp_iu_arena = vmem_create("VSCSI SRP IU", PAGE_SIZE,
724 segs[0].ds_len - PAGE_SIZE, 16, 0, M_BESTFIT | M_NOWAIT);
728 vscsi_setup_bus(struct vscsi_softc *sc)
730 struct vscsi_crq crq;
731 struct vscsi_xfer *xp;
742 char partition_name[96];
743 uint32_t partition_number;
744 uint32_t mad_version;
746 uint32_t port_max_txu[8];
750 bzero(&crq, sizeof(crq));
757 error = phyp_hcall(H_FREE_CRQ, sc->unit);
758 } while (error == H_BUSY);
760 /* See initialization sequence page 757 */
761 bzero(sc->crq_queue, sc->n_crqs*sizeof(sc->crq_queue[0]));
763 sc->bus_initialized = 0;
764 sc->bus_logged_in = 0;
765 bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
766 error = phyp_hcall(H_REG_CRQ, sc->unit, sc->crq_phys,
767 sc->n_crqs*sizeof(sc->crq_queue[0]));
768 KASSERT(error == 0, ("CRQ registration success"));
770 error = phyp_hcall(H_SEND_CRQ, sc->unit, ((uint64_t *)(&crq))[0],
771 ((uint64_t *)(&crq))[1]);
773 panic("CRQ setup failure (%d)", error);
775 while (sc->bus_initialized == 0)
776 vscsi_check_response_queue(sc);
778 /* Send MAD adapter info */
779 mad_adapter_info.type = MAD_ADAPTER_INFO_REQUEST;
780 mad_adapter_info.status = 0;
781 mad_adapter_info.length = sizeof(mad_adapter_info.payload);
783 strcpy(mad_adapter_info.payload.srp_version, "16.a");
784 strcpy(mad_adapter_info.payload.partition_name, "UNKNOWN");
785 mad_adapter_info.payload.partition_number = -1;
786 mad_adapter_info.payload.mad_version = 1;
787 mad_adapter_info.payload.os_type = 2; /* Claim we are Linux */
788 mad_adapter_info.payload.port_max_txu[0] = 0;
789 /* If this fails, we get the defaults above */
790 OF_getprop(OF_finddevice("/"), "ibm,partition-name",
791 mad_adapter_info.payload.partition_name,
792 sizeof(mad_adapter_info.payload.partition_name));
793 OF_getprop(OF_finddevice("/"), "ibm,partition-no",
794 &mad_adapter_info.payload.partition_number,
795 sizeof(mad_adapter_info.payload.partition_number));
797 xp = TAILQ_FIRST(&sc->free_xferq);
799 TAILQ_REMOVE(&sc->free_xferq, xp, queue);
800 TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue);
801 xp->srp_iu_size = crq.iu_length = sizeof(mad_adapter_info);
802 vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size,
803 M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset);
804 mad_adapter_info.buffer = xp->sc->srp_iu_phys + xp->srp_iu_offset + 24;
805 mad_adapter_info.tag = (uint64_t)xp;
806 memcpy((uint8_t *)xp->sc->srp_iu_queue + (uintptr_t)xp->srp_iu_offset,
807 &mad_adapter_info, sizeof(mad_adapter_info));
810 crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset;
811 bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
812 phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0],
813 ((uint64_t *)(&crq))[1]);
815 while (TAILQ_EMPTY(&sc->free_xferq))
816 vscsi_check_response_queue(sc);
820 while (sc->bus_logged_in == 0)
821 vscsi_check_response_queue(sc);
823 error = phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */
828 vscsi_intr(void *xsc)
830 struct vscsi_softc *sc = xsc;
832 mtx_lock(&sc->io_lock);
833 vscsi_check_response_queue(sc);
834 mtx_unlock(&sc->io_lock);
838 vscsi_srp_response(struct vscsi_xfer *xp, struct vscsi_crq *crq)
840 union ccb *ccb = xp->ccb;
841 struct vscsi_softc *sc = xp->sc;
845 /* SRP response packet in original request */
846 rsp = (struct srp_rsp *)((uint8_t *)sc->srp_iu_queue +
847 (uintptr_t)xp->srp_iu_offset);
848 ccb->csio.scsi_status = rsp->status;
849 if (ccb->csio.scsi_status == SCSI_STATUS_OK)
850 ccb->ccb_h.status = CAM_REQ_CMP;
852 ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
854 /* Collect fast fail codes */
855 if (crq->status != 0)
856 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
859 if (ccb->ccb_h.status != CAM_REQ_CMP) {
860 ccb->ccb_h.status |= CAM_DEV_QFRZN;
861 xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
864 if (!(rsp->flags & SRP_RSPVALID))
865 rsp->response_data_len = 0;
866 if (!(rsp->flags & SRP_SNSVALID))
867 rsp->sense_data_len = 0;
868 if (!(rsp->flags & (SRP_DOOVER | SRP_DOUNDER)))
869 rsp->data_out_resid = 0;
870 if (!(rsp->flags & (SRP_DIOVER | SRP_DIUNDER)))
871 rsp->data_in_resid = 0;
873 if (rsp->flags & SRP_SNSVALID) {
874 bzero(&ccb->csio.sense_data, sizeof(struct scsi_sense_data));
875 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
876 sense_len = min(be32toh(rsp->sense_data_len),
877 ccb->csio.sense_len);
878 memcpy(&ccb->csio.sense_data,
879 &rsp->data_payload[be32toh(rsp->response_data_len)],
881 ccb->csio.sense_resid = ccb->csio.sense_len -
882 be32toh(rsp->sense_data_len);
885 switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
887 ccb->csio.resid = rsp->data_out_resid;
890 ccb->csio.resid = rsp->data_in_resid;
894 bus_dmamap_sync(sc->data_tag, xp->dmamap, BUS_DMASYNC_POSTREAD);
895 bus_dmamap_unload(sc->data_tag, xp->dmamap);
901 vscsi_login_response(struct vscsi_xfer *xp, struct vscsi_crq *crq)
903 struct vscsi_softc *sc = xp->sc;
904 struct srp_login_rsp *rsp;
906 /* SRP response packet in original request */
907 rsp = (struct srp_login_rsp *)((uint8_t *)sc->srp_iu_queue +
908 (uintptr_t)xp->srp_iu_offset);
909 KASSERT(be16toh(rsp->buffer_formats) & 0x3, ("Both direct and indirect "
910 "buffers supported"));
912 sc->max_transactions = be32toh(rsp->request_limit_delta);
913 device_printf(sc->dev, "Queue depth %d commands\n",
914 sc->max_transactions);
915 sc->bus_logged_in = 1;
919 vscsi_cam_poll(struct cam_sim *sim)
921 struct vscsi_softc *sc = cam_sim_softc(sim);
923 vscsi_check_response_queue(sc);
927 vscsi_check_response_queue(struct vscsi_softc *sc)
929 struct vscsi_crq *crq;
930 struct vscsi_xfer *xp;
933 mtx_assert(&sc->io_lock, MA_OWNED);
935 while (sc->crq_queue[sc->cur_crq].valid != 0) {
936 /* The hypercalls at both ends of this are not optimal */
937 phyp_hcall(H_VIO_SIGNAL, sc->unit, 0);
938 bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_POSTREAD);
940 crq = &sc->crq_queue[sc->cur_crq];
942 switch (crq->valid) {
944 if (crq->format == 0x02)
945 sc->bus_initialized = 1;
948 /* IU data is set to tag pointer (the XP) */
949 xp = (struct vscsi_xfer *)crq->iu_data;
951 switch (crq->format) {
953 code = *((uint8_t *)sc->srp_iu_queue +
954 (uintptr_t)xp->srp_iu_offset);
957 vscsi_srp_response(xp, crq);
960 vscsi_login_response(xp, crq);
963 device_printf(sc->dev, "Unknown SRP "
964 "response code %d\n", code);
969 /* Ignore management datagrams */
972 panic("Unknown CRQ format %d\n", crq->format);
975 vmem_free(sc->srp_iu_arena, xp->srp_iu_offset,
977 TAILQ_REMOVE(&sc->active_xferq, xp, queue);
978 TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue);
981 device_printf(sc->dev,
982 "Unknown CRQ message type %d\n", crq->valid);
987 sc->cur_crq = (sc->cur_crq + 1) % sc->n_crqs;
989 bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE);
990 phyp_hcall(H_VIO_SIGNAL, sc->unit, 1);