1255927Snwhitehorn/*- 2255927Snwhitehorn * Copyright 2013 Nathan Whitehorn 3255927Snwhitehorn * All rights reserved. 4255927Snwhitehorn * 5255927Snwhitehorn * Redistribution and use in source and binary forms, with or without 6255927Snwhitehorn * modification, are permitted provided that the following conditions 7255927Snwhitehorn * are met: 8255927Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9255927Snwhitehorn * notice, this list of conditions and the following disclaimer. 10255927Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11255927Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12255927Snwhitehorn * documentation and/or other materials provided with the distribution. 13255927Snwhitehorn * 14255927Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15255927Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16255927Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17255927Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18255927Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19255927Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20255927Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21255927Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22255927Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23255927Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24255927Snwhitehorn * SUCH DAMAGE. 25255927Snwhitehorn */ 26255927Snwhitehorn 27255927Snwhitehorn#include <sys/cdefs.h> 28255927Snwhitehorn__FBSDID("$FreeBSD: stable/11/sys/powerpc/pseries/phyp_vscsi.c 315812 2017-03-23 06:40:20Z mav $"); 29255927Snwhitehorn 30255927Snwhitehorn#include <sys/param.h> 31255927Snwhitehorn#include <sys/systm.h> 32255927Snwhitehorn#include <sys/kernel.h> 33255927Snwhitehorn#include <sys/malloc.h> 34255927Snwhitehorn#include <sys/module.h> 35255927Snwhitehorn#include <sys/selinfo.h> 36255927Snwhitehorn#include <sys/bus.h> 37255927Snwhitehorn#include <sys/conf.h> 38255927Snwhitehorn#include <sys/eventhandler.h> 39255927Snwhitehorn#include <sys/rman.h> 40255927Snwhitehorn#include <sys/bus_dma.h> 41255927Snwhitehorn#include <sys/bio.h> 42255927Snwhitehorn#include <sys/ioccom.h> 43255927Snwhitehorn#include <sys/uio.h> 44255927Snwhitehorn#include <sys/proc.h> 45255927Snwhitehorn#include <sys/signalvar.h> 46255927Snwhitehorn#include <sys/sysctl.h> 47255927Snwhitehorn#include <sys/endian.h> 48255927Snwhitehorn#include <sys/vmem.h> 49255927Snwhitehorn 50255927Snwhitehorn#include <cam/cam.h> 51255927Snwhitehorn#include <cam/cam_ccb.h> 52255927Snwhitehorn#include <cam/cam_debug.h> 53255927Snwhitehorn#include <cam/cam_periph.h> 54255927Snwhitehorn#include <cam/cam_sim.h> 55255927Snwhitehorn#include <cam/cam_xpt_periph.h> 56255927Snwhitehorn#include <cam/cam_xpt_sim.h> 57255927Snwhitehorn#include <cam/scsi/scsi_all.h> 58255927Snwhitehorn#include <cam/scsi/scsi_message.h> 59255927Snwhitehorn 60255927Snwhitehorn#include <dev/ofw/openfirm.h> 61255927Snwhitehorn#include <dev/ofw/ofw_bus.h> 62255927Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 63255927Snwhitehorn 64255927Snwhitehorn#include <machine/bus.h> 65255927Snwhitehorn#include <machine/resource.h> 66255927Snwhitehorn 67255927Snwhitehorn#include <powerpc/pseries/phyp-hvcall.h> 68255927Snwhitehorn 69255927Snwhitehornstruct vscsi_softc; 70255927Snwhitehorn 71255927Snwhitehorn/* VSCSI CRQ format from table 260 of PAPR spec 2.4 (page 760) */ 72255927Snwhitehornstruct vscsi_crq { 73255927Snwhitehorn uint8_t valid; 74255927Snwhitehorn uint8_t format; 75255927Snwhitehorn uint8_t reserved; 76255927Snwhitehorn uint8_t status; 77255927Snwhitehorn uint16_t timeout; 78255927Snwhitehorn uint16_t iu_length; 79255927Snwhitehorn uint64_t iu_data; 80255927Snwhitehorn}; 81255927Snwhitehorn 82255927Snwhitehornstruct vscsi_xfer { 83255927Snwhitehorn TAILQ_ENTRY(vscsi_xfer) queue; 84255927Snwhitehorn struct vscsi_softc *sc; 85255927Snwhitehorn union ccb *ccb; 86255927Snwhitehorn bus_dmamap_t dmamap; 87255927Snwhitehorn uint64_t tag; 88255927Snwhitehorn 89255927Snwhitehorn vmem_addr_t srp_iu_offset; 90255927Snwhitehorn vmem_size_t srp_iu_size; 91255927Snwhitehorn}; 92255927Snwhitehorn 93255927SnwhitehornTAILQ_HEAD(vscsi_xferq, vscsi_xfer); 94255927Snwhitehorn 95255927Snwhitehornstruct vscsi_softc { 96255927Snwhitehorn device_t dev; 97255927Snwhitehorn struct cam_devq *devq; 98255927Snwhitehorn struct cam_sim *sim; 99255927Snwhitehorn struct cam_path *path; 100255927Snwhitehorn struct mtx io_lock; 101255927Snwhitehorn 102255927Snwhitehorn cell_t unit; 103255927Snwhitehorn int bus_initialized; 104255927Snwhitehorn int bus_logged_in; 105255927Snwhitehorn int max_transactions; 106255927Snwhitehorn 107255927Snwhitehorn int irqid; 108255927Snwhitehorn struct resource *irq; 109255927Snwhitehorn void *irq_cookie; 110255927Snwhitehorn 111255927Snwhitehorn bus_dma_tag_t crq_tag; 112255927Snwhitehorn struct vscsi_crq *crq_queue; 113255927Snwhitehorn int n_crqs, cur_crq; 114255927Snwhitehorn bus_dmamap_t crq_map; 115255927Snwhitehorn bus_addr_t crq_phys; 116255927Snwhitehorn 117255927Snwhitehorn vmem_t *srp_iu_arena; 118255927Snwhitehorn void *srp_iu_queue; 119255927Snwhitehorn bus_addr_t srp_iu_phys; 120255927Snwhitehorn 121255927Snwhitehorn bus_dma_tag_t data_tag; 122255927Snwhitehorn 123255927Snwhitehorn struct vscsi_xfer loginxp; 124255927Snwhitehorn struct vscsi_xfer *xfer; 125255927Snwhitehorn struct vscsi_xferq active_xferq; 126255927Snwhitehorn struct vscsi_xferq free_xferq; 127255927Snwhitehorn}; 128255927Snwhitehorn 129255927Snwhitehornstruct srp_login { 130255927Snwhitehorn uint8_t type; 131255927Snwhitehorn uint8_t reserved[7]; 132255927Snwhitehorn uint64_t tag; 133255927Snwhitehorn uint64_t max_cmd_length; 134255927Snwhitehorn uint32_t reserved2; 135255927Snwhitehorn uint16_t buffer_formats; 136255927Snwhitehorn uint8_t flags; 137255927Snwhitehorn uint8_t reserved3[5]; 138255927Snwhitehorn uint8_t initiator_port_id[16]; 139255927Snwhitehorn uint8_t target_port_id[16]; 140255927Snwhitehorn} __packed; 141255927Snwhitehorn 142255927Snwhitehornstruct srp_login_rsp { 143255927Snwhitehorn uint8_t type; 144255927Snwhitehorn uint8_t reserved[3]; 145255927Snwhitehorn uint32_t request_limit_delta; 146255927Snwhitehorn uint8_t tag; 147255927Snwhitehorn uint32_t max_i_to_t_len; 148255927Snwhitehorn uint32_t max_t_to_i_len; 149255927Snwhitehorn uint16_t buffer_formats; 150255927Snwhitehorn uint8_t flags; 151255927Snwhitehorn /* Some reserved bits follow */ 152255927Snwhitehorn} __packed; 153255927Snwhitehorn 154255927Snwhitehornstruct srp_cmd { 155255927Snwhitehorn uint8_t type; 156255927Snwhitehorn uint8_t flags1; 157255927Snwhitehorn uint8_t reserved[3]; 158255927Snwhitehorn uint8_t formats; 159255927Snwhitehorn uint8_t out_buffer_count; 160255927Snwhitehorn uint8_t in_buffer_count; 161255927Snwhitehorn uint64_t tag; 162255927Snwhitehorn uint32_t reserved2; 163255927Snwhitehorn uint64_t lun; 164255927Snwhitehorn uint8_t reserved3[3]; 165255927Snwhitehorn uint8_t additional_cdb; 166255927Snwhitehorn uint8_t cdb[16]; 167255927Snwhitehorn uint8_t data_payload[0]; 168255927Snwhitehorn} __packed; 169255927Snwhitehorn 170255927Snwhitehornstruct srp_rsp { 171255927Snwhitehorn uint8_t type; 172255927Snwhitehorn uint8_t reserved[3]; 173255927Snwhitehorn uint32_t request_limit_delta; 174255927Snwhitehorn uint64_t tag; 175255927Snwhitehorn uint16_t reserved2; 176255927Snwhitehorn uint8_t flags; 177255927Snwhitehorn uint8_t status; 178255927Snwhitehorn uint32_t data_out_resid; 179255927Snwhitehorn uint32_t data_in_resid; 180255927Snwhitehorn uint32_t sense_data_len; 181255927Snwhitehorn uint32_t response_data_len; 182255927Snwhitehorn uint8_t data_payload[0]; 183255927Snwhitehorn} __packed; 184255927Snwhitehorn 185255927Snwhitehornstruct srp_tsk_mgmt { 186255927Snwhitehorn uint8_t type; 187255927Snwhitehorn uint8_t reserved[7]; 188255927Snwhitehorn uint64_t tag; 189255927Snwhitehorn uint32_t reserved2; 190255927Snwhitehorn uint64_t lun; 191255927Snwhitehorn uint8_t reserved3[2]; 192255927Snwhitehorn uint8_t function; 193255927Snwhitehorn uint8_t reserved4; 194255927Snwhitehorn uint64_t manage_tag; 195255927Snwhitehorn uint64_t reserved5; 196255927Snwhitehorn} __packed; 197255927Snwhitehorn 198255927Snwhitehorn/* Message code type */ 199255927Snwhitehorn#define SRP_LOGIN_REQ 0x00 200255927Snwhitehorn#define SRP_TSK_MGMT 0x01 201255927Snwhitehorn#define SRP_CMD 0x02 202255927Snwhitehorn#define SRP_I_LOGOUT 0x03 203255927Snwhitehorn 204255927Snwhitehorn#define SRP_LOGIN_RSP 0xC0 205255927Snwhitehorn#define SRP_RSP 0xC1 206255927Snwhitehorn#define SRP_LOGIN_REJ 0xC2 207255927Snwhitehorn 208255927Snwhitehorn#define SRP_T_LOGOUT 0x80 209255927Snwhitehorn#define SRP_CRED_REQ 0x81 210255927Snwhitehorn#define SRP_AER_REQ 0x82 211255927Snwhitehorn 212255927Snwhitehorn#define SRP_CRED_RSP 0x41 213255927Snwhitehorn#define SRP_AER_RSP 0x41 214255927Snwhitehorn 215255927Snwhitehorn/* Flags for srp_rsp flags field */ 216255927Snwhitehorn#define SRP_RSPVALID 0x01 217255927Snwhitehorn#define SRP_SNSVALID 0x02 218255927Snwhitehorn#define SRP_DOOVER 0x04 219255927Snwhitehorn#define SRP_DOUNDER 0x08 220255927Snwhitehorn#define SRP_DIOVER 0x10 221255927Snwhitehorn#define SRP_DIUNDER 0x20 222255927Snwhitehorn 223255927Snwhitehorn#define MAD_SUCESS 0x00 224255927Snwhitehorn#define MAD_NOT_SUPPORTED 0xf1 225255927Snwhitehorn#define MAD_FAILED 0xf7 226255927Snwhitehorn 227255927Snwhitehorn#define MAD_EMPTY_IU 0x01 228255927Snwhitehorn#define MAD_ERROR_LOGGING_REQUEST 0x02 229255927Snwhitehorn#define MAD_ADAPTER_INFO_REQUEST 0x03 230255927Snwhitehorn#define MAD_CAPABILITIES_EXCHANGE 0x05 231255927Snwhitehorn#define MAD_PHYS_ADAP_INFO_REQUEST 0x06 232255927Snwhitehorn#define MAD_TAPE_PASSTHROUGH_REQUEST 0x07 233255927Snwhitehorn#define MAD_ENABLE_FAST_FAIL 0x08 234255927Snwhitehorn 235255927Snwhitehornstatic int vscsi_probe(device_t); 236255927Snwhitehornstatic int vscsi_attach(device_t); 237255927Snwhitehornstatic int vscsi_detach(device_t); 238255927Snwhitehornstatic void vscsi_cam_action(struct cam_sim *, union ccb *); 239255927Snwhitehornstatic void vscsi_cam_poll(struct cam_sim *); 240255927Snwhitehornstatic void vscsi_intr(void *arg); 241255927Snwhitehornstatic void vscsi_check_response_queue(struct vscsi_softc *sc); 242255927Snwhitehornstatic void vscsi_setup_bus(struct vscsi_softc *sc); 243255927Snwhitehorn 244255927Snwhitehornstatic void vscsi_srp_login(struct vscsi_softc *sc); 245255927Snwhitehornstatic void vscsi_crq_load_cb(void *, bus_dma_segment_t *, int, int); 246255927Snwhitehornstatic void vscsi_scsi_command(void *xxp, bus_dma_segment_t *segs, 247255927Snwhitehorn int nsegs, int err); 248255927Snwhitehornstatic void vscsi_task_management(struct vscsi_softc *sc, union ccb *ccb); 249255927Snwhitehornstatic void vscsi_srp_response(struct vscsi_xfer *, struct vscsi_crq *); 250255927Snwhitehorn 251255927Snwhitehornstatic devclass_t vscsi_devclass; 252255927Snwhitehornstatic device_method_t vscsi_methods[] = { 253255927Snwhitehorn DEVMETHOD(device_probe, vscsi_probe), 254255927Snwhitehorn DEVMETHOD(device_attach, vscsi_attach), 255255927Snwhitehorn DEVMETHOD(device_detach, vscsi_detach), 256255927Snwhitehorn 257255927Snwhitehorn DEVMETHOD_END 258255927Snwhitehorn}; 259255927Snwhitehornstatic driver_t vscsi_driver = { 260255927Snwhitehorn "vscsi", 261255927Snwhitehorn vscsi_methods, 262255927Snwhitehorn sizeof(struct vscsi_softc) 263255927Snwhitehorn}; 264255927SnwhitehornDRIVER_MODULE(vscsi, vdevice, vscsi_driver, vscsi_devclass, 0, 0); 265255927SnwhitehornMALLOC_DEFINE(M_VSCSI, "vscsi", "CAM device queue for VSCSI"); 266255927Snwhitehorn 267255927Snwhitehornstatic int 268255927Snwhitehornvscsi_probe(device_t dev) 269255927Snwhitehorn{ 270255927Snwhitehorn 271255927Snwhitehorn if (!ofw_bus_is_compatible(dev, "IBM,v-scsi")) 272255927Snwhitehorn return (ENXIO); 273255927Snwhitehorn 274255927Snwhitehorn device_set_desc(dev, "POWER Hypervisor Virtual SCSI Bus"); 275255927Snwhitehorn return (0); 276255927Snwhitehorn} 277255927Snwhitehorn 278255927Snwhitehornstatic int 279255927Snwhitehornvscsi_attach(device_t dev) 280255927Snwhitehorn{ 281255927Snwhitehorn struct vscsi_softc *sc; 282255927Snwhitehorn struct vscsi_xfer *xp; 283255927Snwhitehorn int error, i; 284255927Snwhitehorn 285255927Snwhitehorn sc = device_get_softc(dev); 286255927Snwhitehorn if (sc == NULL) 287255927Snwhitehorn return (EINVAL); 288255927Snwhitehorn 289255927Snwhitehorn sc->dev = dev; 290255927Snwhitehorn mtx_init(&sc->io_lock, "vscsi", NULL, MTX_DEF); 291255927Snwhitehorn 292255927Snwhitehorn /* Get properties */ 293290989Snwhitehorn OF_getencprop(ofw_bus_get_node(dev), "reg", &sc->unit, 294290989Snwhitehorn sizeof(sc->unit)); 295255927Snwhitehorn 296255927Snwhitehorn /* Setup interrupt */ 297255927Snwhitehorn sc->irqid = 0; 298255927Snwhitehorn sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 299255927Snwhitehorn RF_ACTIVE); 300255927Snwhitehorn 301255927Snwhitehorn if (!sc->irq) { 302255927Snwhitehorn device_printf(dev, "Could not allocate IRQ\n"); 303255927Snwhitehorn mtx_destroy(&sc->io_lock); 304255927Snwhitehorn return (ENXIO); 305255927Snwhitehorn } 306255927Snwhitehorn 307255927Snwhitehorn bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_MPSAFE | 308255927Snwhitehorn INTR_ENTROPY, NULL, vscsi_intr, sc, &sc->irq_cookie); 309255927Snwhitehorn 310255927Snwhitehorn /* Data DMA */ 311255927Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 312255927Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE, 313255927Snwhitehorn 256, BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex, &sc->io_lock, 314255927Snwhitehorn &sc->data_tag); 315255927Snwhitehorn 316255927Snwhitehorn TAILQ_INIT(&sc->active_xferq); 317255927Snwhitehorn TAILQ_INIT(&sc->free_xferq); 318255927Snwhitehorn 319255927Snwhitehorn /* First XFER for login data */ 320255927Snwhitehorn sc->loginxp.sc = sc; 321255927Snwhitehorn bus_dmamap_create(sc->data_tag, 0, &sc->loginxp.dmamap); 322255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, &sc->loginxp, queue); 323255927Snwhitehorn 324255927Snwhitehorn /* CRQ area */ 325255927Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0, 326255927Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 8*PAGE_SIZE, 327255927Snwhitehorn 1, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &sc->crq_tag); 328255927Snwhitehorn error = bus_dmamem_alloc(sc->crq_tag, (void **)&sc->crq_queue, 329255927Snwhitehorn BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->crq_map); 330255927Snwhitehorn sc->crq_phys = 0; 331255927Snwhitehorn sc->n_crqs = 0; 332255927Snwhitehorn error = bus_dmamap_load(sc->crq_tag, sc->crq_map, sc->crq_queue, 333255927Snwhitehorn 8*PAGE_SIZE, vscsi_crq_load_cb, sc, 0); 334255927Snwhitehorn 335255927Snwhitehorn mtx_lock(&sc->io_lock); 336255927Snwhitehorn vscsi_setup_bus(sc); 337255927Snwhitehorn sc->xfer = malloc(sizeof(sc->xfer[0])*sc->max_transactions, M_VSCSI, 338255927Snwhitehorn M_NOWAIT); 339255927Snwhitehorn for (i = 0; i < sc->max_transactions; i++) { 340255927Snwhitehorn xp = &sc->xfer[i]; 341255927Snwhitehorn xp->sc = sc; 342255927Snwhitehorn 343255927Snwhitehorn error = bus_dmamap_create(sc->data_tag, 0, &xp->dmamap); 344255927Snwhitehorn if (error) { 345255927Snwhitehorn device_printf(dev, "Could not create DMA map (%d)\n", 346255927Snwhitehorn error); 347255927Snwhitehorn break; 348255927Snwhitehorn } 349255927Snwhitehorn 350255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue); 351255927Snwhitehorn } 352255927Snwhitehorn mtx_unlock(&sc->io_lock); 353255927Snwhitehorn 354255927Snwhitehorn /* Allocate CAM bits */ 355255927Snwhitehorn if ((sc->devq = cam_simq_alloc(sc->max_transactions)) == NULL) 356255927Snwhitehorn return (ENOMEM); 357255927Snwhitehorn 358255927Snwhitehorn sc->sim = cam_sim_alloc(vscsi_cam_action, vscsi_cam_poll, "vscsi", sc, 359255927Snwhitehorn device_get_unit(dev), &sc->io_lock, 360255927Snwhitehorn sc->max_transactions, sc->max_transactions, 361255927Snwhitehorn sc->devq); 362255927Snwhitehorn if (sc->sim == NULL) { 363255927Snwhitehorn cam_simq_free(sc->devq); 364255927Snwhitehorn sc->devq = NULL; 365255927Snwhitehorn device_printf(dev, "CAM SIM attach failed\n"); 366255927Snwhitehorn return (EINVAL); 367255927Snwhitehorn } 368255927Snwhitehorn 369255927Snwhitehorn 370255927Snwhitehorn mtx_lock(&sc->io_lock); 371255927Snwhitehorn if (xpt_bus_register(sc->sim, dev, 0) != 0) { 372255927Snwhitehorn device_printf(dev, "XPT bus registration failed\n"); 373255927Snwhitehorn cam_sim_free(sc->sim, FALSE); 374255927Snwhitehorn sc->sim = NULL; 375255927Snwhitehorn cam_simq_free(sc->devq); 376255927Snwhitehorn sc->devq = NULL; 377255927Snwhitehorn mtx_unlock(&sc->io_lock); 378255927Snwhitehorn return (EINVAL); 379255927Snwhitehorn } 380255927Snwhitehorn mtx_unlock(&sc->io_lock); 381255927Snwhitehorn 382255927Snwhitehorn return (0); 383255927Snwhitehorn} 384255927Snwhitehorn 385255927Snwhitehornstatic int 386255927Snwhitehornvscsi_detach(device_t dev) 387255927Snwhitehorn{ 388255927Snwhitehorn struct vscsi_softc *sc; 389255927Snwhitehorn 390255927Snwhitehorn sc = device_get_softc(dev); 391255927Snwhitehorn if (sc == NULL) 392255927Snwhitehorn return (EINVAL); 393255927Snwhitehorn 394255927Snwhitehorn if (sc->sim != NULL) { 395255927Snwhitehorn mtx_lock(&sc->io_lock); 396255927Snwhitehorn xpt_bus_deregister(cam_sim_path(sc->sim)); 397255927Snwhitehorn cam_sim_free(sc->sim, FALSE); 398255927Snwhitehorn sc->sim = NULL; 399255927Snwhitehorn mtx_unlock(&sc->io_lock); 400255927Snwhitehorn } 401255927Snwhitehorn 402255927Snwhitehorn if (sc->devq != NULL) { 403255927Snwhitehorn cam_simq_free(sc->devq); 404255927Snwhitehorn sc->devq = NULL; 405255927Snwhitehorn } 406255927Snwhitehorn 407255927Snwhitehorn mtx_destroy(&sc->io_lock); 408255927Snwhitehorn 409255927Snwhitehorn return (0); 410255927Snwhitehorn} 411255927Snwhitehorn 412255927Snwhitehornstatic void 413255927Snwhitehornvscsi_cam_action(struct cam_sim *sim, union ccb *ccb) 414255927Snwhitehorn{ 415255927Snwhitehorn struct vscsi_softc *sc = cam_sim_softc(sim); 416255927Snwhitehorn 417255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 418255927Snwhitehorn 419255927Snwhitehorn switch (ccb->ccb_h.func_code) { 420255927Snwhitehorn case XPT_PATH_INQ: 421255927Snwhitehorn { 422255927Snwhitehorn struct ccb_pathinq *cpi = &ccb->cpi; 423255927Snwhitehorn 424255927Snwhitehorn cpi->version_num = 1; 425255927Snwhitehorn cpi->hba_inquiry = PI_TAG_ABLE; 426255927Snwhitehorn cpi->hba_misc = PIM_EXTLUNS; 427255927Snwhitehorn cpi->target_sprt = 0; 428255927Snwhitehorn cpi->hba_eng_cnt = 0; 429255927Snwhitehorn cpi->max_target = 0; 430259418Snwhitehorn cpi->max_lun = 0; 431255927Snwhitehorn cpi->initiator_id = ~0; 432315812Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 433315812Smav strlcpy(cpi->hba_vid, "IBM", HBA_IDLEN); 434315812Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 435255927Snwhitehorn cpi->unit_number = cam_sim_unit(sim); 436255927Snwhitehorn cpi->bus_id = cam_sim_bus(sim); 437255927Snwhitehorn cpi->base_transfer_speed = 150000; 438255927Snwhitehorn cpi->transport = XPORT_SRP; 439255927Snwhitehorn cpi->transport_version = 0; 440255927Snwhitehorn cpi->protocol = PROTO_SCSI; 441255927Snwhitehorn cpi->protocol_version = SCSI_REV_SPC4; 442255927Snwhitehorn cpi->ccb_h.status = CAM_REQ_CMP; 443255927Snwhitehorn break; 444255927Snwhitehorn } 445255927Snwhitehorn case XPT_RESET_BUS: 446255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 447255927Snwhitehorn break; 448255927Snwhitehorn case XPT_RESET_DEV: 449255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INPROG; 450255927Snwhitehorn vscsi_task_management(sc, ccb); 451255927Snwhitehorn return; 452255927Snwhitehorn case XPT_GET_TRAN_SETTINGS: 453255927Snwhitehorn ccb->cts.protocol = PROTO_SCSI; 454255927Snwhitehorn ccb->cts.protocol_version = SCSI_REV_SPC4; 455255927Snwhitehorn ccb->cts.transport = XPORT_SRP; 456255927Snwhitehorn ccb->cts.transport_version = 0; 457255927Snwhitehorn ccb->cts.proto_specific.valid = 0; 458255927Snwhitehorn ccb->cts.xport_specific.valid = 0; 459255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 460255927Snwhitehorn break; 461255927Snwhitehorn case XPT_SET_TRAN_SETTINGS: 462255927Snwhitehorn ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 463255927Snwhitehorn break; 464255927Snwhitehorn case XPT_SCSI_IO: 465255927Snwhitehorn { 466255927Snwhitehorn struct vscsi_xfer *xp; 467255927Snwhitehorn 468255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INPROG; 469255927Snwhitehorn 470255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 471255927Snwhitehorn if (xp == NULL) 472255927Snwhitehorn panic("SCSI queue flooded"); 473255927Snwhitehorn xp->ccb = ccb; 474255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 475255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 476255927Snwhitehorn bus_dmamap_load_ccb(sc->data_tag, xp->dmamap, 477255927Snwhitehorn ccb, vscsi_scsi_command, xp, 0); 478255927Snwhitehorn 479255927Snwhitehorn return; 480255927Snwhitehorn } 481255927Snwhitehorn default: 482255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INVALID; 483255927Snwhitehorn break; 484255927Snwhitehorn } 485255927Snwhitehorn 486255927Snwhitehorn xpt_done(ccb); 487255927Snwhitehorn return; 488255927Snwhitehorn} 489255927Snwhitehorn 490255927Snwhitehornstatic void 491255927Snwhitehornvscsi_srp_login(struct vscsi_softc *sc) 492255927Snwhitehorn{ 493255927Snwhitehorn struct vscsi_xfer *xp; 494255927Snwhitehorn struct srp_login *login; 495255927Snwhitehorn struct vscsi_crq crq; 496255927Snwhitehorn int err; 497255927Snwhitehorn 498255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 499255927Snwhitehorn 500255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 501255927Snwhitehorn if (xp == NULL) 502255927Snwhitehorn panic("SCSI queue flooded"); 503255927Snwhitehorn xp->ccb = NULL; 504255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 505255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 506255927Snwhitehorn 507255927Snwhitehorn /* Set up command */ 508255927Snwhitehorn xp->srp_iu_size = crq.iu_length = 64; 509255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 510255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 511255927Snwhitehorn if (err) 512255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 513255927Snwhitehorn 514255927Snwhitehorn login = (struct srp_login *)((uint8_t *)xp->sc->srp_iu_queue + 515255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 516255927Snwhitehorn bzero(login, xp->srp_iu_size); 517255927Snwhitehorn login->type = SRP_LOGIN_REQ; 518255927Snwhitehorn login->tag = (uint64_t)(xp); 519255927Snwhitehorn login->max_cmd_length = htobe64(256); 520255927Snwhitehorn login->buffer_formats = htobe16(0x1 | 0x2); /* Direct and indirect */ 521255927Snwhitehorn login->flags = 0; 522255927Snwhitehorn 523255927Snwhitehorn /* Create CRQ entry */ 524255927Snwhitehorn crq.valid = 0x80; 525255927Snwhitehorn crq.format = 0x01; 526255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 527255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 528255927Snwhitehorn 529255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 530255927Snwhitehorn ((uint64_t *)(&crq))[1]); 531255927Snwhitehorn if (err != 0) 532255927Snwhitehorn panic("CRQ send failure (%d)", err); 533255927Snwhitehorn} 534255927Snwhitehorn 535255927Snwhitehornstatic void 536255927Snwhitehornvscsi_task_management(struct vscsi_softc *sc, union ccb *ccb) 537255927Snwhitehorn{ 538255927Snwhitehorn struct srp_tsk_mgmt *cmd; 539255927Snwhitehorn struct vscsi_xfer *xp; 540255927Snwhitehorn struct vscsi_crq crq; 541255927Snwhitehorn int err; 542255927Snwhitehorn 543255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 544255927Snwhitehorn 545255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 546255927Snwhitehorn if (xp == NULL) 547255927Snwhitehorn panic("SCSI queue flooded"); 548255927Snwhitehorn xp->ccb = ccb; 549255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 550255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 551255927Snwhitehorn 552255927Snwhitehorn xp->srp_iu_size = crq.iu_length = sizeof(*cmd); 553255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 554255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 555255927Snwhitehorn if (err) 556255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 557255927Snwhitehorn 558255927Snwhitehorn cmd = (struct srp_tsk_mgmt *)((uint8_t *)xp->sc->srp_iu_queue + 559255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 560255927Snwhitehorn bzero(cmd, xp->srp_iu_size); 561255927Snwhitehorn cmd->type = SRP_TSK_MGMT; 562255927Snwhitehorn cmd->tag = (uint64_t)xp; 563257345Snwhitehorn cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); 564255927Snwhitehorn 565255927Snwhitehorn switch (ccb->ccb_h.func_code) { 566255927Snwhitehorn case XPT_RESET_DEV: 567255927Snwhitehorn cmd->function = 0x08; 568255927Snwhitehorn break; 569255927Snwhitehorn default: 570255927Snwhitehorn panic("Unimplemented code %d", ccb->ccb_h.func_code); 571255927Snwhitehorn break; 572255927Snwhitehorn } 573255927Snwhitehorn 574255927Snwhitehorn bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE); 575255927Snwhitehorn 576255927Snwhitehorn /* Create CRQ entry */ 577255927Snwhitehorn crq.valid = 0x80; 578255927Snwhitehorn crq.format = 0x01; 579255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 580255927Snwhitehorn 581255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 582255927Snwhitehorn ((uint64_t *)(&crq))[1]); 583255927Snwhitehorn if (err != 0) 584255927Snwhitehorn panic("CRQ send failure (%d)", err); 585255927Snwhitehorn} 586255927Snwhitehorn 587255927Snwhitehornstatic void 588255927Snwhitehornvscsi_scsi_command(void *xxp, bus_dma_segment_t *segs, int nsegs, int err) 589255927Snwhitehorn{ 590255927Snwhitehorn struct vscsi_xfer *xp = xxp; 591255927Snwhitehorn uint8_t *cdb; 592255927Snwhitehorn union ccb *ccb = xp->ccb; 593255927Snwhitehorn struct srp_cmd *cmd; 594255927Snwhitehorn uint64_t chunk_addr; 595255927Snwhitehorn uint32_t chunk_size; 596255927Snwhitehorn int desc_start, i; 597255927Snwhitehorn struct vscsi_crq crq; 598255927Snwhitehorn 599255927Snwhitehorn KASSERT(err == 0, ("DMA error %d\n", err)); 600255927Snwhitehorn 601255927Snwhitehorn mtx_assert(&xp->sc->io_lock, MA_OWNED); 602255927Snwhitehorn 603255927Snwhitehorn cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 604255927Snwhitehorn ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes; 605255927Snwhitehorn 606255927Snwhitehorn /* Command format from Table 20, page 37 of SRP spec */ 607255927Snwhitehorn crq.iu_length = 48 + ((nsegs > 1) ? 20 : 16) + 608255927Snwhitehorn ((ccb->csio.cdb_len > 16) ? (ccb->csio.cdb_len - 16) : 0); 609255927Snwhitehorn xp->srp_iu_size = crq.iu_length; 610255927Snwhitehorn if (nsegs > 1) 611255927Snwhitehorn xp->srp_iu_size += nsegs*16; 612255927Snwhitehorn xp->srp_iu_size = roundup(xp->srp_iu_size, 16); 613255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 614255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 615255927Snwhitehorn if (err) 616255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 617255927Snwhitehorn 618255927Snwhitehorn cmd = (struct srp_cmd *)((uint8_t *)xp->sc->srp_iu_queue + 619255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 620255927Snwhitehorn bzero(cmd, xp->srp_iu_size); 621255927Snwhitehorn cmd->type = SRP_CMD; 622255927Snwhitehorn if (ccb->csio.cdb_len > 16) 623255927Snwhitehorn cmd->additional_cdb = (ccb->csio.cdb_len - 16) << 2; 624255927Snwhitehorn memcpy(cmd->cdb, cdb, ccb->csio.cdb_len); 625255927Snwhitehorn 626255927Snwhitehorn cmd->tag = (uint64_t)(xp); /* Let the responder find this again */ 627257345Snwhitehorn cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); 628255927Snwhitehorn 629255927Snwhitehorn if (nsegs > 1) { 630255927Snwhitehorn /* Use indirect descriptors */ 631255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 632255927Snwhitehorn case CAM_DIR_OUT: 633255927Snwhitehorn cmd->formats = (2 << 4); 634255927Snwhitehorn break; 635255927Snwhitehorn case CAM_DIR_IN: 636255927Snwhitehorn cmd->formats = 2; 637255927Snwhitehorn break; 638255927Snwhitehorn default: 639255927Snwhitehorn panic("Does not support bidirectional commands (%d)", 640255927Snwhitehorn ccb->ccb_h.flags & CAM_DIR_MASK); 641255927Snwhitehorn break; 642255927Snwhitehorn } 643255927Snwhitehorn 644255927Snwhitehorn desc_start = ((ccb->csio.cdb_len > 16) ? 645255927Snwhitehorn ccb->csio.cdb_len - 16 : 0); 646255927Snwhitehorn chunk_addr = xp->sc->srp_iu_phys + xp->srp_iu_offset + 20 + 647255927Snwhitehorn desc_start + sizeof(*cmd); 648255927Snwhitehorn chunk_size = 16*nsegs; 649255927Snwhitehorn memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8); 650255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4); 651255927Snwhitehorn chunk_size = 0; 652255927Snwhitehorn for (i = 0; i < nsegs; i++) 653255927Snwhitehorn chunk_size += segs[i].ds_len; 654255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+16], &chunk_size, 4); 655255927Snwhitehorn desc_start += 20; 656255927Snwhitehorn for (i = 0; i < nsegs; i++) { 657255927Snwhitehorn chunk_addr = segs[i].ds_addr; 658255927Snwhitehorn chunk_size = segs[i].ds_len; 659255927Snwhitehorn 660255927Snwhitehorn memcpy(&cmd->data_payload[desc_start + 16*i], 661255927Snwhitehorn &chunk_addr, 8); 662255927Snwhitehorn /* Set handle tag to 0 */ 663255927Snwhitehorn memcpy(&cmd->data_payload[desc_start + 16*i + 12], 664255927Snwhitehorn &chunk_size, 4); 665255927Snwhitehorn } 666255927Snwhitehorn } else if (nsegs == 1) { 667255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 668255927Snwhitehorn case CAM_DIR_OUT: 669255927Snwhitehorn cmd->formats = (1 << 4); 670255927Snwhitehorn break; 671255927Snwhitehorn case CAM_DIR_IN: 672255927Snwhitehorn cmd->formats = 1; 673255927Snwhitehorn break; 674255927Snwhitehorn default: 675255927Snwhitehorn panic("Does not support bidirectional commands (%d)", 676255927Snwhitehorn ccb->ccb_h.flags & CAM_DIR_MASK); 677255927Snwhitehorn break; 678255927Snwhitehorn } 679255927Snwhitehorn 680255927Snwhitehorn /* 681255927Snwhitehorn * Memory descriptor: 682255927Snwhitehorn * 8 byte address 683255927Snwhitehorn * 4 byte handle 684255927Snwhitehorn * 4 byte length 685255927Snwhitehorn */ 686255927Snwhitehorn 687255927Snwhitehorn chunk_addr = segs[0].ds_addr; 688255927Snwhitehorn chunk_size = segs[0].ds_len; 689255927Snwhitehorn desc_start = ((ccb->csio.cdb_len > 16) ? 690255927Snwhitehorn ccb->csio.cdb_len - 16 : 0); 691255927Snwhitehorn 692255927Snwhitehorn memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8); 693255927Snwhitehorn /* Set handle tag to 0 */ 694255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4); 695255927Snwhitehorn KASSERT(xp->srp_iu_size >= 48 + ((ccb->csio.cdb_len > 16) ? 696255927Snwhitehorn ccb->csio.cdb_len : 16), ("SRP IU command length")); 697255927Snwhitehorn } else { 698255927Snwhitehorn cmd->formats = 0; 699255927Snwhitehorn } 700255927Snwhitehorn bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE); 701255927Snwhitehorn 702255927Snwhitehorn /* Create CRQ entry */ 703255927Snwhitehorn crq.valid = 0x80; 704255927Snwhitehorn crq.format = 0x01; 705255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 706255927Snwhitehorn 707255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 708255927Snwhitehorn ((uint64_t *)(&crq))[1]); 709255927Snwhitehorn if (err != 0) 710255927Snwhitehorn panic("CRQ send failure (%d)", err); 711255927Snwhitehorn} 712255927Snwhitehorn 713255927Snwhitehornstatic void 714255927Snwhitehornvscsi_crq_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err) 715255927Snwhitehorn{ 716255927Snwhitehorn struct vscsi_softc *sc = xsc; 717255927Snwhitehorn 718255927Snwhitehorn sc->crq_phys = segs[0].ds_addr; 719255927Snwhitehorn sc->n_crqs = PAGE_SIZE/sizeof(struct vscsi_crq); 720255927Snwhitehorn 721255927Snwhitehorn sc->srp_iu_queue = (uint8_t *)(sc->crq_queue); 722255927Snwhitehorn sc->srp_iu_phys = segs[0].ds_addr; 723255927Snwhitehorn sc->srp_iu_arena = vmem_create("VSCSI SRP IU", PAGE_SIZE, 724255927Snwhitehorn segs[0].ds_len - PAGE_SIZE, 16, 0, M_BESTFIT | M_NOWAIT); 725255927Snwhitehorn} 726255927Snwhitehorn 727255927Snwhitehornstatic void 728255927Snwhitehornvscsi_setup_bus(struct vscsi_softc *sc) 729255927Snwhitehorn{ 730255927Snwhitehorn struct vscsi_crq crq; 731255927Snwhitehorn struct vscsi_xfer *xp; 732255927Snwhitehorn int error; 733255927Snwhitehorn 734255927Snwhitehorn struct { 735255927Snwhitehorn uint32_t type; 736255927Snwhitehorn uint16_t status; 737255927Snwhitehorn uint16_t length; 738255927Snwhitehorn uint64_t tag; 739255927Snwhitehorn uint64_t buffer; 740255927Snwhitehorn struct { 741255927Snwhitehorn char srp_version[8]; 742255927Snwhitehorn char partition_name[96]; 743255927Snwhitehorn uint32_t partition_number; 744255927Snwhitehorn uint32_t mad_version; 745255927Snwhitehorn uint32_t os_type; 746255927Snwhitehorn uint32_t port_max_txu[8]; 747255927Snwhitehorn } payload; 748255927Snwhitehorn } mad_adapter_info; 749255927Snwhitehorn 750255927Snwhitehorn bzero(&crq, sizeof(crq)); 751255927Snwhitehorn 752255927Snwhitehorn /* Init message */ 753255927Snwhitehorn crq.valid = 0xc0; 754255927Snwhitehorn crq.format = 0x01; 755255927Snwhitehorn 756255927Snwhitehorn do { 757255927Snwhitehorn error = phyp_hcall(H_FREE_CRQ, sc->unit); 758255927Snwhitehorn } while (error == H_BUSY); 759255927Snwhitehorn 760255927Snwhitehorn /* See initialization sequence page 757 */ 761255927Snwhitehorn bzero(sc->crq_queue, sc->n_crqs*sizeof(sc->crq_queue[0])); 762255927Snwhitehorn sc->cur_crq = 0; 763255927Snwhitehorn sc->bus_initialized = 0; 764255927Snwhitehorn sc->bus_logged_in = 0; 765255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 766255927Snwhitehorn error = phyp_hcall(H_REG_CRQ, sc->unit, sc->crq_phys, 767255927Snwhitehorn sc->n_crqs*sizeof(sc->crq_queue[0])); 768255927Snwhitehorn KASSERT(error == 0, ("CRQ registration success")); 769255927Snwhitehorn 770255927Snwhitehorn error = phyp_hcall(H_SEND_CRQ, sc->unit, ((uint64_t *)(&crq))[0], 771255927Snwhitehorn ((uint64_t *)(&crq))[1]); 772255927Snwhitehorn if (error != 0) 773255927Snwhitehorn panic("CRQ setup failure (%d)", error); 774255927Snwhitehorn 775255927Snwhitehorn while (sc->bus_initialized == 0) 776255927Snwhitehorn vscsi_check_response_queue(sc); 777255927Snwhitehorn 778255927Snwhitehorn /* Send MAD adapter info */ 779255927Snwhitehorn mad_adapter_info.type = MAD_ADAPTER_INFO_REQUEST; 780255927Snwhitehorn mad_adapter_info.status = 0; 781255927Snwhitehorn mad_adapter_info.length = sizeof(mad_adapter_info.payload); 782255927Snwhitehorn 783255927Snwhitehorn strcpy(mad_adapter_info.payload.srp_version, "16.a"); 784255927Snwhitehorn strcpy(mad_adapter_info.payload.partition_name, "UNKNOWN"); 785255927Snwhitehorn mad_adapter_info.payload.partition_number = -1; 786255927Snwhitehorn mad_adapter_info.payload.mad_version = 1; 787255927Snwhitehorn mad_adapter_info.payload.os_type = 2; /* Claim we are Linux */ 788255927Snwhitehorn mad_adapter_info.payload.port_max_txu[0] = 0; 789255927Snwhitehorn /* If this fails, we get the defaults above */ 790255927Snwhitehorn OF_getprop(OF_finddevice("/"), "ibm,partition-name", 791255927Snwhitehorn mad_adapter_info.payload.partition_name, 792255927Snwhitehorn sizeof(mad_adapter_info.payload.partition_name)); 793255927Snwhitehorn OF_getprop(OF_finddevice("/"), "ibm,partition-no", 794255927Snwhitehorn &mad_adapter_info.payload.partition_number, 795255927Snwhitehorn sizeof(mad_adapter_info.payload.partition_number)); 796255927Snwhitehorn 797255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 798255927Snwhitehorn xp->ccb = NULL; 799255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 800255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 801255927Snwhitehorn xp->srp_iu_size = crq.iu_length = sizeof(mad_adapter_info); 802255927Snwhitehorn vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 803255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 804255927Snwhitehorn mad_adapter_info.buffer = xp->sc->srp_iu_phys + xp->srp_iu_offset + 24; 805255927Snwhitehorn mad_adapter_info.tag = (uint64_t)xp; 806255927Snwhitehorn memcpy((uint8_t *)xp->sc->srp_iu_queue + (uintptr_t)xp->srp_iu_offset, 807255927Snwhitehorn &mad_adapter_info, sizeof(mad_adapter_info)); 808255927Snwhitehorn crq.valid = 0x80; 809255927Snwhitehorn crq.format = 0x02; 810255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 811255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 812255927Snwhitehorn phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 813255927Snwhitehorn ((uint64_t *)(&crq))[1]); 814255927Snwhitehorn 815255927Snwhitehorn while (TAILQ_EMPTY(&sc->free_xferq)) 816255927Snwhitehorn vscsi_check_response_queue(sc); 817255927Snwhitehorn 818255927Snwhitehorn /* Send SRP login */ 819255927Snwhitehorn vscsi_srp_login(sc); 820255927Snwhitehorn while (sc->bus_logged_in == 0) 821255927Snwhitehorn vscsi_check_response_queue(sc); 822255927Snwhitehorn 823255927Snwhitehorn error = phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */ 824255927Snwhitehorn} 825255927Snwhitehorn 826255927Snwhitehorn 827255927Snwhitehornstatic void 828255927Snwhitehornvscsi_intr(void *xsc) 829255927Snwhitehorn{ 830255927Snwhitehorn struct vscsi_softc *sc = xsc; 831255927Snwhitehorn 832255927Snwhitehorn mtx_lock(&sc->io_lock); 833255927Snwhitehorn vscsi_check_response_queue(sc); 834255927Snwhitehorn mtx_unlock(&sc->io_lock); 835255927Snwhitehorn} 836255927Snwhitehorn 837255927Snwhitehornstatic void 838255927Snwhitehornvscsi_srp_response(struct vscsi_xfer *xp, struct vscsi_crq *crq) 839255927Snwhitehorn{ 840255927Snwhitehorn union ccb *ccb = xp->ccb; 841255927Snwhitehorn struct vscsi_softc *sc = xp->sc; 842255927Snwhitehorn struct srp_rsp *rsp; 843255927Snwhitehorn uint32_t sense_len; 844255927Snwhitehorn 845255927Snwhitehorn /* SRP response packet in original request */ 846255927Snwhitehorn rsp = (struct srp_rsp *)((uint8_t *)sc->srp_iu_queue + 847255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 848255927Snwhitehorn ccb->csio.scsi_status = rsp->status; 849255927Snwhitehorn if (ccb->csio.scsi_status == SCSI_STATUS_OK) 850255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 851255927Snwhitehorn else 852255927Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 853255927Snwhitehorn#ifdef NOTYET 854255927Snwhitehorn /* Collect fast fail codes */ 855255927Snwhitehorn if (crq->status != 0) 856255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP_ERR; 857255927Snwhitehorn#endif 858255927Snwhitehorn 859255927Snwhitehorn if (ccb->ccb_h.status != CAM_REQ_CMP) { 860255927Snwhitehorn ccb->ccb_h.status |= CAM_DEV_QFRZN; 861255927Snwhitehorn xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 862255927Snwhitehorn } 863255927Snwhitehorn 864255927Snwhitehorn if (!(rsp->flags & SRP_RSPVALID)) 865255927Snwhitehorn rsp->response_data_len = 0; 866255927Snwhitehorn if (!(rsp->flags & SRP_SNSVALID)) 867255927Snwhitehorn rsp->sense_data_len = 0; 868255927Snwhitehorn if (!(rsp->flags & (SRP_DOOVER | SRP_DOUNDER))) 869255927Snwhitehorn rsp->data_out_resid = 0; 870255927Snwhitehorn if (!(rsp->flags & (SRP_DIOVER | SRP_DIUNDER))) 871255927Snwhitehorn rsp->data_in_resid = 0; 872255927Snwhitehorn 873255927Snwhitehorn if (rsp->flags & SRP_SNSVALID) { 874255927Snwhitehorn bzero(&ccb->csio.sense_data, sizeof(struct scsi_sense_data)); 875255927Snwhitehorn ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 876255927Snwhitehorn sense_len = min(be32toh(rsp->sense_data_len), 877255927Snwhitehorn ccb->csio.sense_len); 878255927Snwhitehorn memcpy(&ccb->csio.sense_data, 879255927Snwhitehorn &rsp->data_payload[be32toh(rsp->response_data_len)], 880255927Snwhitehorn sense_len); 881255927Snwhitehorn ccb->csio.sense_resid = ccb->csio.sense_len - 882255927Snwhitehorn be32toh(rsp->sense_data_len); 883255927Snwhitehorn } 884255927Snwhitehorn 885255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 886255927Snwhitehorn case CAM_DIR_OUT: 887255927Snwhitehorn ccb->csio.resid = rsp->data_out_resid; 888255927Snwhitehorn break; 889255927Snwhitehorn case CAM_DIR_IN: 890255927Snwhitehorn ccb->csio.resid = rsp->data_in_resid; 891255927Snwhitehorn break; 892255927Snwhitehorn } 893255927Snwhitehorn 894255927Snwhitehorn bus_dmamap_sync(sc->data_tag, xp->dmamap, BUS_DMASYNC_POSTREAD); 895255927Snwhitehorn bus_dmamap_unload(sc->data_tag, xp->dmamap); 896255927Snwhitehorn xpt_done(ccb); 897255927Snwhitehorn xp->ccb = NULL; 898255927Snwhitehorn} 899255927Snwhitehorn 900255927Snwhitehornstatic void 901255927Snwhitehornvscsi_login_response(struct vscsi_xfer *xp, struct vscsi_crq *crq) 902255927Snwhitehorn{ 903255927Snwhitehorn struct vscsi_softc *sc = xp->sc; 904255927Snwhitehorn struct srp_login_rsp *rsp; 905255927Snwhitehorn 906255927Snwhitehorn /* SRP response packet in original request */ 907255927Snwhitehorn rsp = (struct srp_login_rsp *)((uint8_t *)sc->srp_iu_queue + 908255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 909255927Snwhitehorn KASSERT(be16toh(rsp->buffer_formats) & 0x3, ("Both direct and indirect " 910255927Snwhitehorn "buffers supported")); 911255927Snwhitehorn 912255927Snwhitehorn sc->max_transactions = be32toh(rsp->request_limit_delta); 913255927Snwhitehorn device_printf(sc->dev, "Queue depth %d commands\n", 914255927Snwhitehorn sc->max_transactions); 915255927Snwhitehorn sc->bus_logged_in = 1; 916255927Snwhitehorn} 917255927Snwhitehorn 918255927Snwhitehornstatic void 919255927Snwhitehornvscsi_cam_poll(struct cam_sim *sim) 920255927Snwhitehorn{ 921255927Snwhitehorn struct vscsi_softc *sc = cam_sim_softc(sim); 922255927Snwhitehorn 923255927Snwhitehorn vscsi_check_response_queue(sc); 924255927Snwhitehorn} 925255927Snwhitehorn 926255927Snwhitehornstatic void 927255927Snwhitehornvscsi_check_response_queue(struct vscsi_softc *sc) 928255927Snwhitehorn{ 929255927Snwhitehorn struct vscsi_crq *crq; 930255927Snwhitehorn struct vscsi_xfer *xp; 931255927Snwhitehorn int code; 932255927Snwhitehorn 933255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 934255927Snwhitehorn 935279217Snwhitehorn while (sc->crq_queue[sc->cur_crq].valid != 0) { 936279217Snwhitehorn /* The hypercalls at both ends of this are not optimal */ 937279217Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 0); 938279217Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_POSTREAD); 939255927Snwhitehorn 940255927Snwhitehorn crq = &sc->crq_queue[sc->cur_crq]; 941255927Snwhitehorn 942255927Snwhitehorn switch (crq->valid) { 943255927Snwhitehorn case 0xc0: 944255927Snwhitehorn if (crq->format == 0x02) 945255927Snwhitehorn sc->bus_initialized = 1; 946255927Snwhitehorn break; 947255927Snwhitehorn case 0x80: 948255927Snwhitehorn /* IU data is set to tag pointer (the XP) */ 949255927Snwhitehorn xp = (struct vscsi_xfer *)crq->iu_data; 950255927Snwhitehorn 951255927Snwhitehorn switch (crq->format) { 952255927Snwhitehorn case 0x01: 953255927Snwhitehorn code = *((uint8_t *)sc->srp_iu_queue + 954255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 955255927Snwhitehorn switch (code) { 956255927Snwhitehorn case SRP_RSP: 957255927Snwhitehorn vscsi_srp_response(xp, crq); 958255927Snwhitehorn break; 959255927Snwhitehorn case SRP_LOGIN_RSP: 960255927Snwhitehorn vscsi_login_response(xp, crq); 961255927Snwhitehorn break; 962255927Snwhitehorn default: 963255927Snwhitehorn device_printf(sc->dev, "Unknown SRP " 964255927Snwhitehorn "response code %d\n", code); 965255927Snwhitehorn break; 966255927Snwhitehorn } 967255927Snwhitehorn break; 968255927Snwhitehorn case 0x02: 969255927Snwhitehorn /* Ignore management datagrams */ 970255927Snwhitehorn break; 971255927Snwhitehorn default: 972255927Snwhitehorn panic("Unknown CRQ format %d\n", crq->format); 973255927Snwhitehorn break; 974255927Snwhitehorn } 975255927Snwhitehorn vmem_free(sc->srp_iu_arena, xp->srp_iu_offset, 976255927Snwhitehorn xp->srp_iu_size); 977255927Snwhitehorn TAILQ_REMOVE(&sc->active_xferq, xp, queue); 978255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue); 979255927Snwhitehorn break; 980255927Snwhitehorn default: 981255927Snwhitehorn device_printf(sc->dev, 982255927Snwhitehorn "Unknown CRQ message type %d\n", crq->valid); 983255927Snwhitehorn break; 984255927Snwhitehorn } 985255927Snwhitehorn 986255927Snwhitehorn crq->valid = 0; 987255927Snwhitehorn sc->cur_crq = (sc->cur_crq + 1) % sc->n_crqs; 988255927Snwhitehorn 989279217Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 990279217Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); 991279217Snwhitehorn } 992255927Snwhitehorn} 993255927Snwhitehorn 994