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: releng/10.3/sys/powerpc/pseries/phyp_vscsi.c 259204 2013-12-10 22:55:22Z nwhitehorn $"); 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 */ 293255927Snwhitehorn OF_getprop(ofw_bus_get_node(dev), "reg", &sc->unit, sizeof(sc->unit)); 294255927Snwhitehorn 295255927Snwhitehorn /* Setup interrupt */ 296255927Snwhitehorn sc->irqid = 0; 297255927Snwhitehorn sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 298255927Snwhitehorn RF_ACTIVE); 299255927Snwhitehorn 300255927Snwhitehorn if (!sc->irq) { 301255927Snwhitehorn device_printf(dev, "Could not allocate IRQ\n"); 302255927Snwhitehorn mtx_destroy(&sc->io_lock); 303255927Snwhitehorn return (ENXIO); 304255927Snwhitehorn } 305255927Snwhitehorn 306255927Snwhitehorn bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_MPSAFE | 307255927Snwhitehorn INTR_ENTROPY, NULL, vscsi_intr, sc, &sc->irq_cookie); 308255927Snwhitehorn 309255927Snwhitehorn /* Data DMA */ 310255927Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 311255927Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE, 312255927Snwhitehorn 256, BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex, &sc->io_lock, 313255927Snwhitehorn &sc->data_tag); 314255927Snwhitehorn 315255927Snwhitehorn TAILQ_INIT(&sc->active_xferq); 316255927Snwhitehorn TAILQ_INIT(&sc->free_xferq); 317255927Snwhitehorn 318255927Snwhitehorn /* First XFER for login data */ 319255927Snwhitehorn sc->loginxp.sc = sc; 320255927Snwhitehorn bus_dmamap_create(sc->data_tag, 0, &sc->loginxp.dmamap); 321255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, &sc->loginxp, queue); 322255927Snwhitehorn 323255927Snwhitehorn /* CRQ area */ 324255927Snwhitehorn error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0, 325255927Snwhitehorn BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 8*PAGE_SIZE, 326255927Snwhitehorn 1, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &sc->crq_tag); 327255927Snwhitehorn error = bus_dmamem_alloc(sc->crq_tag, (void **)&sc->crq_queue, 328255927Snwhitehorn BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->crq_map); 329255927Snwhitehorn sc->crq_phys = 0; 330255927Snwhitehorn sc->n_crqs = 0; 331255927Snwhitehorn error = bus_dmamap_load(sc->crq_tag, sc->crq_map, sc->crq_queue, 332255927Snwhitehorn 8*PAGE_SIZE, vscsi_crq_load_cb, sc, 0); 333255927Snwhitehorn 334255927Snwhitehorn mtx_lock(&sc->io_lock); 335255927Snwhitehorn vscsi_setup_bus(sc); 336255927Snwhitehorn sc->xfer = malloc(sizeof(sc->xfer[0])*sc->max_transactions, M_VSCSI, 337255927Snwhitehorn M_NOWAIT); 338255927Snwhitehorn for (i = 0; i < sc->max_transactions; i++) { 339255927Snwhitehorn xp = &sc->xfer[i]; 340255927Snwhitehorn xp->sc = sc; 341255927Snwhitehorn 342255927Snwhitehorn error = bus_dmamap_create(sc->data_tag, 0, &xp->dmamap); 343255927Snwhitehorn if (error) { 344255927Snwhitehorn device_printf(dev, "Could not create DMA map (%d)\n", 345255927Snwhitehorn error); 346255927Snwhitehorn break; 347255927Snwhitehorn } 348255927Snwhitehorn 349255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue); 350255927Snwhitehorn } 351255927Snwhitehorn mtx_unlock(&sc->io_lock); 352255927Snwhitehorn 353255927Snwhitehorn /* Allocate CAM bits */ 354255927Snwhitehorn if ((sc->devq = cam_simq_alloc(sc->max_transactions)) == NULL) 355255927Snwhitehorn return (ENOMEM); 356255927Snwhitehorn 357255927Snwhitehorn sc->sim = cam_sim_alloc(vscsi_cam_action, vscsi_cam_poll, "vscsi", sc, 358255927Snwhitehorn device_get_unit(dev), &sc->io_lock, 359255927Snwhitehorn sc->max_transactions, sc->max_transactions, 360255927Snwhitehorn sc->devq); 361255927Snwhitehorn if (sc->sim == NULL) { 362255927Snwhitehorn cam_simq_free(sc->devq); 363255927Snwhitehorn sc->devq = NULL; 364255927Snwhitehorn device_printf(dev, "CAM SIM attach failed\n"); 365255927Snwhitehorn return (EINVAL); 366255927Snwhitehorn } 367255927Snwhitehorn 368255927Snwhitehorn 369255927Snwhitehorn mtx_lock(&sc->io_lock); 370255927Snwhitehorn if (xpt_bus_register(sc->sim, dev, 0) != 0) { 371255927Snwhitehorn device_printf(dev, "XPT bus registration failed\n"); 372255927Snwhitehorn cam_sim_free(sc->sim, FALSE); 373255927Snwhitehorn sc->sim = NULL; 374255927Snwhitehorn cam_simq_free(sc->devq); 375255927Snwhitehorn sc->devq = NULL; 376255927Snwhitehorn mtx_unlock(&sc->io_lock); 377255927Snwhitehorn return (EINVAL); 378255927Snwhitehorn } 379255927Snwhitehorn mtx_unlock(&sc->io_lock); 380255927Snwhitehorn 381255927Snwhitehorn return (0); 382255927Snwhitehorn} 383255927Snwhitehorn 384255927Snwhitehornstatic int 385255927Snwhitehornvscsi_detach(device_t dev) 386255927Snwhitehorn{ 387255927Snwhitehorn struct vscsi_softc *sc; 388255927Snwhitehorn 389255927Snwhitehorn sc = device_get_softc(dev); 390255927Snwhitehorn if (sc == NULL) 391255927Snwhitehorn return (EINVAL); 392255927Snwhitehorn 393255927Snwhitehorn if (sc->sim != NULL) { 394255927Snwhitehorn mtx_lock(&sc->io_lock); 395255927Snwhitehorn xpt_bus_deregister(cam_sim_path(sc->sim)); 396255927Snwhitehorn cam_sim_free(sc->sim, FALSE); 397255927Snwhitehorn sc->sim = NULL; 398255927Snwhitehorn mtx_unlock(&sc->io_lock); 399255927Snwhitehorn } 400255927Snwhitehorn 401255927Snwhitehorn if (sc->devq != NULL) { 402255927Snwhitehorn cam_simq_free(sc->devq); 403255927Snwhitehorn sc->devq = NULL; 404255927Snwhitehorn } 405255927Snwhitehorn 406255927Snwhitehorn mtx_destroy(&sc->io_lock); 407255927Snwhitehorn 408255927Snwhitehorn return (0); 409255927Snwhitehorn} 410255927Snwhitehorn 411255927Snwhitehornstatic void 412255927Snwhitehornvscsi_cam_action(struct cam_sim *sim, union ccb *ccb) 413255927Snwhitehorn{ 414255927Snwhitehorn struct vscsi_softc *sc = cam_sim_softc(sim); 415255927Snwhitehorn 416255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 417255927Snwhitehorn 418255927Snwhitehorn switch (ccb->ccb_h.func_code) { 419255927Snwhitehorn case XPT_PATH_INQ: 420255927Snwhitehorn { 421255927Snwhitehorn struct ccb_pathinq *cpi = &ccb->cpi; 422255927Snwhitehorn 423255927Snwhitehorn cpi->version_num = 1; 424255927Snwhitehorn cpi->hba_inquiry = PI_TAG_ABLE; 425255927Snwhitehorn cpi->hba_misc = PIM_EXTLUNS; 426255927Snwhitehorn cpi->target_sprt = 0; 427255927Snwhitehorn cpi->hba_eng_cnt = 0; 428255927Snwhitehorn cpi->max_target = 0; 429255927Snwhitehorn cpi->max_lun = ~(lun_id_t)(0); 430255927Snwhitehorn cpi->initiator_id = ~0; 431255927Snwhitehorn strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 432255927Snwhitehorn strncpy(cpi->hba_vid, "IBM", HBA_IDLEN); 433255927Snwhitehorn strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 434255927Snwhitehorn cpi->unit_number = cam_sim_unit(sim); 435255927Snwhitehorn cpi->bus_id = cam_sim_bus(sim); 436255927Snwhitehorn cpi->base_transfer_speed = 150000; 437255927Snwhitehorn cpi->transport = XPORT_SRP; 438255927Snwhitehorn cpi->transport_version = 0; 439255927Snwhitehorn cpi->protocol = PROTO_SCSI; 440255927Snwhitehorn cpi->protocol_version = SCSI_REV_SPC4; 441255927Snwhitehorn cpi->ccb_h.status = CAM_REQ_CMP; 442255927Snwhitehorn break; 443255927Snwhitehorn } 444255927Snwhitehorn case XPT_RESET_BUS: 445255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 446255927Snwhitehorn break; 447255927Snwhitehorn case XPT_RESET_DEV: 448255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INPROG; 449255927Snwhitehorn vscsi_task_management(sc, ccb); 450255927Snwhitehorn return; 451255927Snwhitehorn case XPT_GET_TRAN_SETTINGS: 452255927Snwhitehorn ccb->cts.protocol = PROTO_SCSI; 453255927Snwhitehorn ccb->cts.protocol_version = SCSI_REV_SPC4; 454255927Snwhitehorn ccb->cts.transport = XPORT_SRP; 455255927Snwhitehorn ccb->cts.transport_version = 0; 456255927Snwhitehorn ccb->cts.proto_specific.valid = 0; 457255927Snwhitehorn ccb->cts.xport_specific.valid = 0; 458255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 459255927Snwhitehorn break; 460255927Snwhitehorn case XPT_SET_TRAN_SETTINGS: 461255927Snwhitehorn ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 462255927Snwhitehorn break; 463255927Snwhitehorn case XPT_SCSI_IO: 464255927Snwhitehorn { 465255927Snwhitehorn struct vscsi_xfer *xp; 466255927Snwhitehorn 467255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INPROG; 468255927Snwhitehorn 469255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 470255927Snwhitehorn if (xp == NULL) 471255927Snwhitehorn panic("SCSI queue flooded"); 472255927Snwhitehorn xp->ccb = ccb; 473255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 474255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 475255927Snwhitehorn bus_dmamap_load_ccb(sc->data_tag, xp->dmamap, 476255927Snwhitehorn ccb, vscsi_scsi_command, xp, 0); 477255927Snwhitehorn 478255927Snwhitehorn return; 479255927Snwhitehorn } 480255927Snwhitehorn default: 481255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_INVALID; 482255927Snwhitehorn break; 483255927Snwhitehorn } 484255927Snwhitehorn 485255927Snwhitehorn xpt_done(ccb); 486255927Snwhitehorn return; 487255927Snwhitehorn} 488255927Snwhitehorn 489255927Snwhitehornstatic void 490255927Snwhitehornvscsi_srp_login(struct vscsi_softc *sc) 491255927Snwhitehorn{ 492255927Snwhitehorn struct vscsi_xfer *xp; 493255927Snwhitehorn struct srp_login *login; 494255927Snwhitehorn struct vscsi_crq crq; 495255927Snwhitehorn int err; 496255927Snwhitehorn 497255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 498255927Snwhitehorn 499255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 500255927Snwhitehorn if (xp == NULL) 501255927Snwhitehorn panic("SCSI queue flooded"); 502255927Snwhitehorn xp->ccb = NULL; 503255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 504255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 505255927Snwhitehorn 506255927Snwhitehorn /* Set up command */ 507255927Snwhitehorn xp->srp_iu_size = crq.iu_length = 64; 508255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 509255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 510255927Snwhitehorn if (err) 511255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 512255927Snwhitehorn 513255927Snwhitehorn login = (struct srp_login *)((uint8_t *)xp->sc->srp_iu_queue + 514255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 515255927Snwhitehorn bzero(login, xp->srp_iu_size); 516255927Snwhitehorn login->type = SRP_LOGIN_REQ; 517255927Snwhitehorn login->tag = (uint64_t)(xp); 518255927Snwhitehorn login->max_cmd_length = htobe64(256); 519255927Snwhitehorn login->buffer_formats = htobe16(0x1 | 0x2); /* Direct and indirect */ 520255927Snwhitehorn login->flags = 0; 521255927Snwhitehorn 522255927Snwhitehorn /* Create CRQ entry */ 523255927Snwhitehorn crq.valid = 0x80; 524255927Snwhitehorn crq.format = 0x01; 525255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 526255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 527255927Snwhitehorn 528255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 529255927Snwhitehorn ((uint64_t *)(&crq))[1]); 530255927Snwhitehorn if (err != 0) 531255927Snwhitehorn panic("CRQ send failure (%d)", err); 532255927Snwhitehorn} 533255927Snwhitehorn 534255927Snwhitehornstatic void 535255927Snwhitehornvscsi_task_management(struct vscsi_softc *sc, union ccb *ccb) 536255927Snwhitehorn{ 537255927Snwhitehorn struct srp_tsk_mgmt *cmd; 538255927Snwhitehorn struct vscsi_xfer *xp; 539255927Snwhitehorn struct vscsi_crq crq; 540255927Snwhitehorn int err; 541255927Snwhitehorn 542255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 543255927Snwhitehorn 544255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 545255927Snwhitehorn if (xp == NULL) 546255927Snwhitehorn panic("SCSI queue flooded"); 547255927Snwhitehorn xp->ccb = ccb; 548255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 549255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 550255927Snwhitehorn 551255927Snwhitehorn xp->srp_iu_size = crq.iu_length = sizeof(*cmd); 552255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 553255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 554255927Snwhitehorn if (err) 555255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 556255927Snwhitehorn 557255927Snwhitehorn cmd = (struct srp_tsk_mgmt *)((uint8_t *)xp->sc->srp_iu_queue + 558255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 559255927Snwhitehorn bzero(cmd, xp->srp_iu_size); 560255927Snwhitehorn cmd->type = SRP_TSK_MGMT; 561255927Snwhitehorn cmd->tag = (uint64_t)xp; 562259204Snwhitehorn cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); 563255927Snwhitehorn 564255927Snwhitehorn switch (ccb->ccb_h.func_code) { 565255927Snwhitehorn case XPT_RESET_DEV: 566255927Snwhitehorn cmd->function = 0x08; 567255927Snwhitehorn break; 568255927Snwhitehorn default: 569255927Snwhitehorn panic("Unimplemented code %d", ccb->ccb_h.func_code); 570255927Snwhitehorn break; 571255927Snwhitehorn } 572255927Snwhitehorn 573255927Snwhitehorn bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE); 574255927Snwhitehorn 575255927Snwhitehorn /* Create CRQ entry */ 576255927Snwhitehorn crq.valid = 0x80; 577255927Snwhitehorn crq.format = 0x01; 578255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 579255927Snwhitehorn 580255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 581255927Snwhitehorn ((uint64_t *)(&crq))[1]); 582255927Snwhitehorn if (err != 0) 583255927Snwhitehorn panic("CRQ send failure (%d)", err); 584255927Snwhitehorn} 585255927Snwhitehorn 586255927Snwhitehornstatic void 587255927Snwhitehornvscsi_scsi_command(void *xxp, bus_dma_segment_t *segs, int nsegs, int err) 588255927Snwhitehorn{ 589255927Snwhitehorn struct vscsi_xfer *xp = xxp; 590255927Snwhitehorn uint8_t *cdb; 591255927Snwhitehorn union ccb *ccb = xp->ccb; 592255927Snwhitehorn struct srp_cmd *cmd; 593255927Snwhitehorn uint64_t chunk_addr; 594255927Snwhitehorn uint32_t chunk_size; 595255927Snwhitehorn int desc_start, i; 596255927Snwhitehorn struct vscsi_crq crq; 597255927Snwhitehorn 598255927Snwhitehorn KASSERT(err == 0, ("DMA error %d\n", err)); 599255927Snwhitehorn 600255927Snwhitehorn mtx_assert(&xp->sc->io_lock, MA_OWNED); 601255927Snwhitehorn 602255927Snwhitehorn cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ? 603255927Snwhitehorn ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes; 604255927Snwhitehorn 605255927Snwhitehorn /* Command format from Table 20, page 37 of SRP spec */ 606255927Snwhitehorn crq.iu_length = 48 + ((nsegs > 1) ? 20 : 16) + 607255927Snwhitehorn ((ccb->csio.cdb_len > 16) ? (ccb->csio.cdb_len - 16) : 0); 608255927Snwhitehorn xp->srp_iu_size = crq.iu_length; 609255927Snwhitehorn if (nsegs > 1) 610255927Snwhitehorn xp->srp_iu_size += nsegs*16; 611255927Snwhitehorn xp->srp_iu_size = roundup(xp->srp_iu_size, 16); 612255927Snwhitehorn err = vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 613255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 614255927Snwhitehorn if (err) 615255927Snwhitehorn panic("Error during VMEM allocation (%d)", err); 616255927Snwhitehorn 617255927Snwhitehorn cmd = (struct srp_cmd *)((uint8_t *)xp->sc->srp_iu_queue + 618255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 619255927Snwhitehorn bzero(cmd, xp->srp_iu_size); 620255927Snwhitehorn cmd->type = SRP_CMD; 621255927Snwhitehorn if (ccb->csio.cdb_len > 16) 622255927Snwhitehorn cmd->additional_cdb = (ccb->csio.cdb_len - 16) << 2; 623255927Snwhitehorn memcpy(cmd->cdb, cdb, ccb->csio.cdb_len); 624255927Snwhitehorn 625255927Snwhitehorn cmd->tag = (uint64_t)(xp); /* Let the responder find this again */ 626259204Snwhitehorn cmd->lun = htobe64(CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun)); 627255927Snwhitehorn 628255927Snwhitehorn if (nsegs > 1) { 629255927Snwhitehorn /* Use indirect descriptors */ 630255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 631255927Snwhitehorn case CAM_DIR_OUT: 632255927Snwhitehorn cmd->formats = (2 << 4); 633255927Snwhitehorn break; 634255927Snwhitehorn case CAM_DIR_IN: 635255927Snwhitehorn cmd->formats = 2; 636255927Snwhitehorn break; 637255927Snwhitehorn default: 638255927Snwhitehorn panic("Does not support bidirectional commands (%d)", 639255927Snwhitehorn ccb->ccb_h.flags & CAM_DIR_MASK); 640255927Snwhitehorn break; 641255927Snwhitehorn } 642255927Snwhitehorn 643255927Snwhitehorn desc_start = ((ccb->csio.cdb_len > 16) ? 644255927Snwhitehorn ccb->csio.cdb_len - 16 : 0); 645255927Snwhitehorn chunk_addr = xp->sc->srp_iu_phys + xp->srp_iu_offset + 20 + 646255927Snwhitehorn desc_start + sizeof(*cmd); 647255927Snwhitehorn chunk_size = 16*nsegs; 648255927Snwhitehorn memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8); 649255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4); 650255927Snwhitehorn chunk_size = 0; 651255927Snwhitehorn for (i = 0; i < nsegs; i++) 652255927Snwhitehorn chunk_size += segs[i].ds_len; 653255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+16], &chunk_size, 4); 654255927Snwhitehorn desc_start += 20; 655255927Snwhitehorn for (i = 0; i < nsegs; i++) { 656255927Snwhitehorn chunk_addr = segs[i].ds_addr; 657255927Snwhitehorn chunk_size = segs[i].ds_len; 658255927Snwhitehorn 659255927Snwhitehorn memcpy(&cmd->data_payload[desc_start + 16*i], 660255927Snwhitehorn &chunk_addr, 8); 661255927Snwhitehorn /* Set handle tag to 0 */ 662255927Snwhitehorn memcpy(&cmd->data_payload[desc_start + 16*i + 12], 663255927Snwhitehorn &chunk_size, 4); 664255927Snwhitehorn } 665255927Snwhitehorn } else if (nsegs == 1) { 666255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 667255927Snwhitehorn case CAM_DIR_OUT: 668255927Snwhitehorn cmd->formats = (1 << 4); 669255927Snwhitehorn break; 670255927Snwhitehorn case CAM_DIR_IN: 671255927Snwhitehorn cmd->formats = 1; 672255927Snwhitehorn break; 673255927Snwhitehorn default: 674255927Snwhitehorn panic("Does not support bidirectional commands (%d)", 675255927Snwhitehorn ccb->ccb_h.flags & CAM_DIR_MASK); 676255927Snwhitehorn break; 677255927Snwhitehorn } 678255927Snwhitehorn 679255927Snwhitehorn /* 680255927Snwhitehorn * Memory descriptor: 681255927Snwhitehorn * 8 byte address 682255927Snwhitehorn * 4 byte handle 683255927Snwhitehorn * 4 byte length 684255927Snwhitehorn */ 685255927Snwhitehorn 686255927Snwhitehorn chunk_addr = segs[0].ds_addr; 687255927Snwhitehorn chunk_size = segs[0].ds_len; 688255927Snwhitehorn desc_start = ((ccb->csio.cdb_len > 16) ? 689255927Snwhitehorn ccb->csio.cdb_len - 16 : 0); 690255927Snwhitehorn 691255927Snwhitehorn memcpy(&cmd->data_payload[desc_start], &chunk_addr, 8); 692255927Snwhitehorn /* Set handle tag to 0 */ 693255927Snwhitehorn memcpy(&cmd->data_payload[desc_start+12], &chunk_size, 4); 694255927Snwhitehorn KASSERT(xp->srp_iu_size >= 48 + ((ccb->csio.cdb_len > 16) ? 695255927Snwhitehorn ccb->csio.cdb_len : 16), ("SRP IU command length")); 696255927Snwhitehorn } else { 697255927Snwhitehorn cmd->formats = 0; 698255927Snwhitehorn } 699255927Snwhitehorn bus_dmamap_sync(xp->sc->crq_tag, xp->sc->crq_map, BUS_DMASYNC_PREWRITE); 700255927Snwhitehorn 701255927Snwhitehorn /* Create CRQ entry */ 702255927Snwhitehorn crq.valid = 0x80; 703255927Snwhitehorn crq.format = 0x01; 704255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 705255927Snwhitehorn 706255927Snwhitehorn err = phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 707255927Snwhitehorn ((uint64_t *)(&crq))[1]); 708255927Snwhitehorn if (err != 0) 709255927Snwhitehorn panic("CRQ send failure (%d)", err); 710255927Snwhitehorn} 711255927Snwhitehorn 712255927Snwhitehornstatic void 713255927Snwhitehornvscsi_crq_load_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int err) 714255927Snwhitehorn{ 715255927Snwhitehorn struct vscsi_softc *sc = xsc; 716255927Snwhitehorn 717255927Snwhitehorn sc->crq_phys = segs[0].ds_addr; 718255927Snwhitehorn sc->n_crqs = PAGE_SIZE/sizeof(struct vscsi_crq); 719255927Snwhitehorn 720255927Snwhitehorn sc->srp_iu_queue = (uint8_t *)(sc->crq_queue); 721255927Snwhitehorn sc->srp_iu_phys = segs[0].ds_addr; 722255927Snwhitehorn sc->srp_iu_arena = vmem_create("VSCSI SRP IU", PAGE_SIZE, 723255927Snwhitehorn segs[0].ds_len - PAGE_SIZE, 16, 0, M_BESTFIT | M_NOWAIT); 724255927Snwhitehorn} 725255927Snwhitehorn 726255927Snwhitehornstatic void 727255927Snwhitehornvscsi_setup_bus(struct vscsi_softc *sc) 728255927Snwhitehorn{ 729255927Snwhitehorn struct vscsi_crq crq; 730255927Snwhitehorn struct vscsi_xfer *xp; 731255927Snwhitehorn int error; 732255927Snwhitehorn 733255927Snwhitehorn struct { 734255927Snwhitehorn uint32_t type; 735255927Snwhitehorn uint16_t status; 736255927Snwhitehorn uint16_t length; 737255927Snwhitehorn uint64_t tag; 738255927Snwhitehorn uint64_t buffer; 739255927Snwhitehorn struct { 740255927Snwhitehorn char srp_version[8]; 741255927Snwhitehorn char partition_name[96]; 742255927Snwhitehorn uint32_t partition_number; 743255927Snwhitehorn uint32_t mad_version; 744255927Snwhitehorn uint32_t os_type; 745255927Snwhitehorn uint32_t port_max_txu[8]; 746255927Snwhitehorn } payload; 747255927Snwhitehorn } mad_adapter_info; 748255927Snwhitehorn 749255927Snwhitehorn bzero(&crq, sizeof(crq)); 750255927Snwhitehorn 751255927Snwhitehorn /* Init message */ 752255927Snwhitehorn crq.valid = 0xc0; 753255927Snwhitehorn crq.format = 0x01; 754255927Snwhitehorn 755255927Snwhitehorn do { 756255927Snwhitehorn error = phyp_hcall(H_FREE_CRQ, sc->unit); 757255927Snwhitehorn } while (error == H_BUSY); 758255927Snwhitehorn 759255927Snwhitehorn /* See initialization sequence page 757 */ 760255927Snwhitehorn bzero(sc->crq_queue, sc->n_crqs*sizeof(sc->crq_queue[0])); 761255927Snwhitehorn sc->cur_crq = 0; 762255927Snwhitehorn sc->bus_initialized = 0; 763255927Snwhitehorn sc->bus_logged_in = 0; 764255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 765255927Snwhitehorn error = phyp_hcall(H_REG_CRQ, sc->unit, sc->crq_phys, 766255927Snwhitehorn sc->n_crqs*sizeof(sc->crq_queue[0])); 767255927Snwhitehorn KASSERT(error == 0, ("CRQ registration success")); 768255927Snwhitehorn 769255927Snwhitehorn error = phyp_hcall(H_SEND_CRQ, sc->unit, ((uint64_t *)(&crq))[0], 770255927Snwhitehorn ((uint64_t *)(&crq))[1]); 771255927Snwhitehorn if (error != 0) 772255927Snwhitehorn panic("CRQ setup failure (%d)", error); 773255927Snwhitehorn 774255927Snwhitehorn while (sc->bus_initialized == 0) 775255927Snwhitehorn vscsi_check_response_queue(sc); 776255927Snwhitehorn 777255927Snwhitehorn /* Send MAD adapter info */ 778255927Snwhitehorn mad_adapter_info.type = MAD_ADAPTER_INFO_REQUEST; 779255927Snwhitehorn mad_adapter_info.status = 0; 780255927Snwhitehorn mad_adapter_info.length = sizeof(mad_adapter_info.payload); 781255927Snwhitehorn 782255927Snwhitehorn strcpy(mad_adapter_info.payload.srp_version, "16.a"); 783255927Snwhitehorn strcpy(mad_adapter_info.payload.partition_name, "UNKNOWN"); 784255927Snwhitehorn mad_adapter_info.payload.partition_number = -1; 785255927Snwhitehorn mad_adapter_info.payload.mad_version = 1; 786255927Snwhitehorn mad_adapter_info.payload.os_type = 2; /* Claim we are Linux */ 787255927Snwhitehorn mad_adapter_info.payload.port_max_txu[0] = 0; 788255927Snwhitehorn /* If this fails, we get the defaults above */ 789255927Snwhitehorn OF_getprop(OF_finddevice("/"), "ibm,partition-name", 790255927Snwhitehorn mad_adapter_info.payload.partition_name, 791255927Snwhitehorn sizeof(mad_adapter_info.payload.partition_name)); 792255927Snwhitehorn OF_getprop(OF_finddevice("/"), "ibm,partition-no", 793255927Snwhitehorn &mad_adapter_info.payload.partition_number, 794255927Snwhitehorn sizeof(mad_adapter_info.payload.partition_number)); 795255927Snwhitehorn 796255927Snwhitehorn xp = TAILQ_FIRST(&sc->free_xferq); 797255927Snwhitehorn xp->ccb = NULL; 798255927Snwhitehorn TAILQ_REMOVE(&sc->free_xferq, xp, queue); 799255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->active_xferq, xp, queue); 800255927Snwhitehorn xp->srp_iu_size = crq.iu_length = sizeof(mad_adapter_info); 801255927Snwhitehorn vmem_alloc(xp->sc->srp_iu_arena, xp->srp_iu_size, 802255927Snwhitehorn M_BESTFIT | M_NOWAIT, &xp->srp_iu_offset); 803255927Snwhitehorn mad_adapter_info.buffer = xp->sc->srp_iu_phys + xp->srp_iu_offset + 24; 804255927Snwhitehorn mad_adapter_info.tag = (uint64_t)xp; 805255927Snwhitehorn memcpy((uint8_t *)xp->sc->srp_iu_queue + (uintptr_t)xp->srp_iu_offset, 806255927Snwhitehorn &mad_adapter_info, sizeof(mad_adapter_info)); 807255927Snwhitehorn crq.valid = 0x80; 808255927Snwhitehorn crq.format = 0x02; 809255927Snwhitehorn crq.iu_data = xp->sc->srp_iu_phys + xp->srp_iu_offset; 810255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 811255927Snwhitehorn phyp_hcall(H_SEND_CRQ, xp->sc->unit, ((uint64_t *)(&crq))[0], 812255927Snwhitehorn ((uint64_t *)(&crq))[1]); 813255927Snwhitehorn 814255927Snwhitehorn while (TAILQ_EMPTY(&sc->free_xferq)) 815255927Snwhitehorn vscsi_check_response_queue(sc); 816255927Snwhitehorn 817255927Snwhitehorn /* Send SRP login */ 818255927Snwhitehorn vscsi_srp_login(sc); 819255927Snwhitehorn while (sc->bus_logged_in == 0) 820255927Snwhitehorn vscsi_check_response_queue(sc); 821255927Snwhitehorn 822255927Snwhitehorn error = phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); /* Enable interrupts */ 823255927Snwhitehorn} 824255927Snwhitehorn 825255927Snwhitehorn 826255927Snwhitehornstatic void 827255927Snwhitehornvscsi_intr(void *xsc) 828255927Snwhitehorn{ 829255927Snwhitehorn struct vscsi_softc *sc = xsc; 830255927Snwhitehorn 831255927Snwhitehorn mtx_lock(&sc->io_lock); 832255927Snwhitehorn vscsi_check_response_queue(sc); 833255927Snwhitehorn mtx_unlock(&sc->io_lock); 834255927Snwhitehorn} 835255927Snwhitehorn 836255927Snwhitehornstatic void 837255927Snwhitehornvscsi_srp_response(struct vscsi_xfer *xp, struct vscsi_crq *crq) 838255927Snwhitehorn{ 839255927Snwhitehorn union ccb *ccb = xp->ccb; 840255927Snwhitehorn struct vscsi_softc *sc = xp->sc; 841255927Snwhitehorn struct srp_rsp *rsp; 842255927Snwhitehorn uint32_t sense_len; 843255927Snwhitehorn 844255927Snwhitehorn /* SRP response packet in original request */ 845255927Snwhitehorn rsp = (struct srp_rsp *)((uint8_t *)sc->srp_iu_queue + 846255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 847255927Snwhitehorn ccb->csio.scsi_status = rsp->status; 848255927Snwhitehorn if (ccb->csio.scsi_status == SCSI_STATUS_OK) 849255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP; 850255927Snwhitehorn else 851255927Snwhitehorn ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 852255927Snwhitehorn#ifdef NOTYET 853255927Snwhitehorn /* Collect fast fail codes */ 854255927Snwhitehorn if (crq->status != 0) 855255927Snwhitehorn ccb->ccb_h.status = CAM_REQ_CMP_ERR; 856255927Snwhitehorn#endif 857255927Snwhitehorn 858255927Snwhitehorn if (ccb->ccb_h.status != CAM_REQ_CMP) { 859255927Snwhitehorn ccb->ccb_h.status |= CAM_DEV_QFRZN; 860255927Snwhitehorn xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 861255927Snwhitehorn } 862255927Snwhitehorn 863255927Snwhitehorn if (!(rsp->flags & SRP_RSPVALID)) 864255927Snwhitehorn rsp->response_data_len = 0; 865255927Snwhitehorn if (!(rsp->flags & SRP_SNSVALID)) 866255927Snwhitehorn rsp->sense_data_len = 0; 867255927Snwhitehorn if (!(rsp->flags & (SRP_DOOVER | SRP_DOUNDER))) 868255927Snwhitehorn rsp->data_out_resid = 0; 869255927Snwhitehorn if (!(rsp->flags & (SRP_DIOVER | SRP_DIUNDER))) 870255927Snwhitehorn rsp->data_in_resid = 0; 871255927Snwhitehorn 872255927Snwhitehorn if (rsp->flags & SRP_SNSVALID) { 873255927Snwhitehorn bzero(&ccb->csio.sense_data, sizeof(struct scsi_sense_data)); 874255927Snwhitehorn ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 875255927Snwhitehorn sense_len = min(be32toh(rsp->sense_data_len), 876255927Snwhitehorn ccb->csio.sense_len); 877255927Snwhitehorn memcpy(&ccb->csio.sense_data, 878255927Snwhitehorn &rsp->data_payload[be32toh(rsp->response_data_len)], 879255927Snwhitehorn sense_len); 880255927Snwhitehorn ccb->csio.sense_resid = ccb->csio.sense_len - 881255927Snwhitehorn be32toh(rsp->sense_data_len); 882255927Snwhitehorn } 883255927Snwhitehorn 884255927Snwhitehorn switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 885255927Snwhitehorn case CAM_DIR_OUT: 886255927Snwhitehorn ccb->csio.resid = rsp->data_out_resid; 887255927Snwhitehorn break; 888255927Snwhitehorn case CAM_DIR_IN: 889255927Snwhitehorn ccb->csio.resid = rsp->data_in_resid; 890255927Snwhitehorn break; 891255927Snwhitehorn } 892255927Snwhitehorn 893255927Snwhitehorn bus_dmamap_sync(sc->data_tag, xp->dmamap, BUS_DMASYNC_POSTREAD); 894255927Snwhitehorn bus_dmamap_unload(sc->data_tag, xp->dmamap); 895255927Snwhitehorn xpt_done(ccb); 896255927Snwhitehorn xp->ccb = NULL; 897255927Snwhitehorn} 898255927Snwhitehorn 899255927Snwhitehornstatic void 900255927Snwhitehornvscsi_login_response(struct vscsi_xfer *xp, struct vscsi_crq *crq) 901255927Snwhitehorn{ 902255927Snwhitehorn struct vscsi_softc *sc = xp->sc; 903255927Snwhitehorn struct srp_login_rsp *rsp; 904255927Snwhitehorn 905255927Snwhitehorn /* SRP response packet in original request */ 906255927Snwhitehorn rsp = (struct srp_login_rsp *)((uint8_t *)sc->srp_iu_queue + 907255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 908255927Snwhitehorn KASSERT(be16toh(rsp->buffer_formats) & 0x3, ("Both direct and indirect " 909255927Snwhitehorn "buffers supported")); 910255927Snwhitehorn 911255927Snwhitehorn sc->max_transactions = be32toh(rsp->request_limit_delta); 912255927Snwhitehorn device_printf(sc->dev, "Queue depth %d commands\n", 913255927Snwhitehorn sc->max_transactions); 914255927Snwhitehorn sc->bus_logged_in = 1; 915255927Snwhitehorn} 916255927Snwhitehorn 917255927Snwhitehornstatic void 918255927Snwhitehornvscsi_cam_poll(struct cam_sim *sim) 919255927Snwhitehorn{ 920255927Snwhitehorn struct vscsi_softc *sc = cam_sim_softc(sim); 921255927Snwhitehorn 922255927Snwhitehorn vscsi_check_response_queue(sc); 923255927Snwhitehorn} 924255927Snwhitehorn 925255927Snwhitehornstatic void 926255927Snwhitehornvscsi_check_response_queue(struct vscsi_softc *sc) 927255927Snwhitehorn{ 928255927Snwhitehorn struct vscsi_crq *crq; 929255927Snwhitehorn struct vscsi_xfer *xp; 930255927Snwhitehorn int code; 931255927Snwhitehorn 932255927Snwhitehorn mtx_assert(&sc->io_lock, MA_OWNED); 933255927Snwhitehorn 934255927Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 0); 935255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_POSTREAD); 936255927Snwhitehorn 937255927Snwhitehorn while (sc->crq_queue[sc->cur_crq].valid != 0) { 938255927Snwhitehorn crq = &sc->crq_queue[sc->cur_crq]; 939255927Snwhitehorn 940255927Snwhitehorn switch (crq->valid) { 941255927Snwhitehorn case 0xc0: 942255927Snwhitehorn if (crq->format == 0x02) 943255927Snwhitehorn sc->bus_initialized = 1; 944255927Snwhitehorn break; 945255927Snwhitehorn case 0x80: 946255927Snwhitehorn /* IU data is set to tag pointer (the XP) */ 947255927Snwhitehorn xp = (struct vscsi_xfer *)crq->iu_data; 948255927Snwhitehorn 949255927Snwhitehorn switch (crq->format) { 950255927Snwhitehorn case 0x01: 951255927Snwhitehorn code = *((uint8_t *)sc->srp_iu_queue + 952255927Snwhitehorn (uintptr_t)xp->srp_iu_offset); 953255927Snwhitehorn switch (code) { 954255927Snwhitehorn case SRP_RSP: 955255927Snwhitehorn vscsi_srp_response(xp, crq); 956255927Snwhitehorn break; 957255927Snwhitehorn case SRP_LOGIN_RSP: 958255927Snwhitehorn vscsi_login_response(xp, crq); 959255927Snwhitehorn break; 960255927Snwhitehorn default: 961255927Snwhitehorn device_printf(sc->dev, "Unknown SRP " 962255927Snwhitehorn "response code %d\n", code); 963255927Snwhitehorn break; 964255927Snwhitehorn } 965255927Snwhitehorn break; 966255927Snwhitehorn case 0x02: 967255927Snwhitehorn /* Ignore management datagrams */ 968255927Snwhitehorn break; 969255927Snwhitehorn default: 970255927Snwhitehorn panic("Unknown CRQ format %d\n", crq->format); 971255927Snwhitehorn break; 972255927Snwhitehorn } 973255927Snwhitehorn vmem_free(sc->srp_iu_arena, xp->srp_iu_offset, 974255927Snwhitehorn xp->srp_iu_size); 975255927Snwhitehorn TAILQ_REMOVE(&sc->active_xferq, xp, queue); 976255927Snwhitehorn TAILQ_INSERT_TAIL(&sc->free_xferq, xp, queue); 977255927Snwhitehorn break; 978255927Snwhitehorn default: 979255927Snwhitehorn device_printf(sc->dev, 980255927Snwhitehorn "Unknown CRQ message type %d\n", crq->valid); 981255927Snwhitehorn break; 982255927Snwhitehorn } 983255927Snwhitehorn 984255927Snwhitehorn crq->valid = 0; 985255927Snwhitehorn sc->cur_crq = (sc->cur_crq + 1) % sc->n_crqs; 986255927Snwhitehorn }; 987255927Snwhitehorn 988255927Snwhitehorn bus_dmamap_sync(sc->crq_tag, sc->crq_map, BUS_DMASYNC_PREWRITE); 989255927Snwhitehorn phyp_hcall(H_VIO_SIGNAL, sc->unit, 1); 990255927Snwhitehorn} 991255927Snwhitehorn 992