ctl_frontend.c revision 284798
190284Sobrien/*- 290284Sobrien * Copyright (c) 2003 Silicon Graphics International Corp. 3169705Skan * All rights reserved. 418334Speter * 5132743Skan * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 7132743Skan * are met: 818334Speter * 1. Redistributions of source code must retain the above copyright 918334Speter * notice, this list of conditions, and the following disclaimer, 1018334Speter * without modification. 1118334Speter * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12132743Skan * substantially similar to the "NO WARRANTY" disclaimer below 1318334Speter * ("Disclaimer") and any redistribution must be conditioned upon 1418334Speter * including a substantially similar Disclaimer requirement for further 1518334Speter * binary redistribution. 1618334Speter * 1718334Speter * NO WARRANTY 18132743Skan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19169705Skan * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20169705Skan * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 2118334Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2251411Sobrien * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2351411Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2418334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2551411Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26132743Skan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27132743Skan * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2818334Speter * POSSIBILITY OF SUCH DAMAGES. 2990284Sobrien * 3090284Sobrien * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend.c#4 $ 3118334Speter */ 3218334Speter/* 3318334Speter * CAM Target Layer front end interface code 3418334Speter * 3518334Speter * Author: Ken Merry <ken@FreeBSD.org> 3618334Speter */ 37169705Skan 3818334Speter#include <sys/cdefs.h> 3918334Speter__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_frontend.c 284798 2015-06-25 07:11:48Z mav $"); 4051411Sobrien 4118334Speter#include <sys/param.h> 4251411Sobrien#include <sys/systm.h> 4351411Sobrien#include <sys/kernel.h> 4490284Sobrien#include <sys/types.h> 4551411Sobrien#include <sys/malloc.h> 4690284Sobrien#include <sys/lock.h> 4790284Sobrien#include <sys/mutex.h> 4890284Sobrien#include <sys/condvar.h> 4990284Sobrien#include <sys/endian.h> 50117408Skan#include <sys/queue.h> 51132743Skan#include <sys/sysctl.h> 52169705Skan 53169705Skan#include <cam/scsi/scsi_all.h> 54169705Skan#include <cam/scsi/scsi_da.h> 5518334Speter#include <cam/ctl/ctl_io.h> 5651411Sobrien#include <cam/ctl/ctl.h> 5790284Sobrien#include <cam/ctl/ctl_frontend.h> 5851411Sobrien#include <cam/ctl/ctl_frontend_internal.h> 5918334Speter#include <cam/ctl/ctl_backend.h> 60132743Skan/* XXX KDM move defines from ctl_ioctl.h to somewhere else */ 61132743Skan#include <cam/ctl/ctl_ioctl.h> 62132743Skan#include <cam/ctl/ctl_ha.h> 63132743Skan#include <cam/ctl/ctl_private.h> 64132743Skan#include <cam/ctl/ctl_debug.h> 65132743Skan 66132743Skanextern struct ctl_softc *control_softc; 67132743Skan 6890284Sobrienint 69169705Skanctl_frontend_register(struct ctl_frontend *fe) 70169705Skan{ 71169705Skan struct ctl_softc *softc = control_softc; 72117408Skan struct ctl_frontend *fe_tmp; 73169705Skan 74169705Skan KASSERT(softc != NULL, ("CTL is not initialized")); 75169705Skan 76169705Skan /* 77169705Skan * Sanity check, make sure this isn't a duplicate registration. 78169705Skan */ 79169705Skan mtx_lock(&softc->ctl_lock); 80169705Skan STAILQ_FOREACH(fe_tmp, &softc->fe_list, links) { 81169705Skan if (strcmp(fe_tmp->name, fe->name) == 0) { 82169705Skan mtx_unlock(&softc->ctl_lock); 8390284Sobrien return (-1); 84169705Skan } 85169705Skan } 86169705Skan mtx_unlock(&softc->ctl_lock); 87169705Skan STAILQ_INIT(&fe->port_list); 88169705Skan 89169705Skan /* 90169705Skan * Call the frontend's initialization routine. 9190284Sobrien */ 9290284Sobrien if (fe->init != NULL) 9390284Sobrien fe->init(); 9490284Sobrien 9590284Sobrien mtx_lock(&softc->ctl_lock); 9690284Sobrien softc->num_frontends++; 9790284Sobrien STAILQ_INSERT_TAIL(&softc->fe_list, fe, links); 9890284Sobrien mtx_unlock(&softc->ctl_lock); 9990284Sobrien return (0); 10090284Sobrien} 101169705Skan 102169705Skanint 10390284Sobrienctl_frontend_deregister(struct ctl_frontend *fe) 10490284Sobrien{ 10590284Sobrien struct ctl_softc *softc = control_softc; 10690284Sobrien 10790284Sobrien if (!STAILQ_EMPTY(&fe->port_list)) 10890284Sobrien return (-1); 10990284Sobrien 11090284Sobrien mtx_lock(&softc->ctl_lock); 11190284Sobrien STAILQ_REMOVE(&softc->fe_list, fe, ctl_frontend, links); 11290284Sobrien softc->num_frontends--; 11390284Sobrien mtx_unlock(&softc->ctl_lock); 11490284Sobrien 11590284Sobrien /* 116169705Skan * Call the frontend's shutdown routine. 117169705Skan */ 118169705Skan if (fe->shutdown != NULL) 119169705Skan fe->shutdown(); 120169705Skan return (0); 121169705Skan} 122169705Skan 12351411Sobrienstruct ctl_frontend * 124117408Skanctl_frontend_find(char *frontend_name) 12551411Sobrien{ 126117408Skan struct ctl_softc *softc = control_softc; 12751411Sobrien struct ctl_frontend *fe; 128169705Skan 129169705Skan mtx_lock(&softc->ctl_lock); 130169705Skan STAILQ_FOREACH(fe, &softc->fe_list, links) { 131169705Skan if (strcmp(fe->name, frontend_name) == 0) { 132169705Skan mtx_unlock(&softc->ctl_lock); 133169705Skan return (fe); 134169705Skan } 135169705Skan } 136169705Skan mtx_unlock(&softc->ctl_lock); 137169705Skan return (NULL); 138169705Skan} 139169705Skan 140169705Skanint 141169705Skanctl_port_register(struct ctl_port *port) 142169705Skan{ 143169705Skan struct ctl_softc *softc = control_softc; 144169705Skan void *pool; 14590284Sobrien int port_num; 14690284Sobrien int retval; 14790284Sobrien 14890284Sobrien retval = 0; 14990284Sobrien 15090284Sobrien KASSERT(softc != NULL, ("CTL is not initialized")); 15190284Sobrien 15290284Sobrien mtx_lock(&softc->ctl_lock); 15390284Sobrien port_num = ctl_ffz(softc->ctl_port_mask, CTL_MAX_PORTS); 15490284Sobrien if ((port_num == -1) 155169705Skan || (ctl_set_mask(softc->ctl_port_mask, port_num) == -1)) { 156169705Skan port->targ_port = -1; 15790284Sobrien mtx_unlock(&softc->ctl_lock); 15890284Sobrien return (1); 15990284Sobrien } 16090284Sobrien softc->num_ports++; 16190284Sobrien mtx_unlock(&softc->ctl_lock); 16290284Sobrien 16390284Sobrien /* 16490284Sobrien * Initialize the initiator and portname mappings 16590284Sobrien */ 16690284Sobrien port->max_initiators = CTL_MAX_INIT_PER_PORT; 16790284Sobrien port->wwpn_iid = malloc(sizeof(*port->wwpn_iid) * port->max_initiators, 16890284Sobrien M_CTL, M_NOWAIT | M_ZERO); 16990284Sobrien if (port->wwpn_iid == NULL) { 170132743Skan retval = ENOMEM; 171169705Skan goto error; 172169705Skan } 173169705Skan 174169705Skan /* 175169705Skan * We add 20 to whatever the caller requests, so he doesn't get 176169705Skan * burned by queueing things back to the pending sense queue. In 17751411Sobrien * theory, there should probably only be one outstanding item, at 17851411Sobrien * most, on the pending sense queue for a LUN. We'll clear the 179117408Skan * pending sense queue on the next command, whether or not it is 18051411Sobrien * a REQUEST SENSE. 181169705Skan */ 182169705Skan retval = ctl_pool_create(softc, port->port_name, 183169705Skan port->num_requested_ctl_io + 20, &pool); 184169705Skan if (retval != 0) { 185169705Skan free(port->wwpn_iid, M_CTL); 186169705Skanerror: 187169705Skan port->targ_port = -1; 188169705Skan mtx_lock(&softc->ctl_lock); 189169705Skan ctl_clear_mask(softc->ctl_port_mask, port_num); 19051411Sobrien mtx_unlock(&softc->ctl_lock); 191169705Skan return (retval); 192169705Skan } 193169705Skan port->ctl_pool_ref = pool; 194169705Skan 195169705Skan if (port->options.stqh_first == NULL) 196169705Skan STAILQ_INIT(&port->options); 197169705Skan 19890284Sobrien mtx_lock(&softc->ctl_lock); 19990284Sobrien port->targ_port = port_num + softc->port_offset; 20090284Sobrien STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links); 20190284Sobrien STAILQ_INSERT_TAIL(&softc->port_list, port, links); 20290284Sobrien softc->ctl_ports[port_num] = port; 20390284Sobrien mtx_unlock(&softc->ctl_lock); 20490284Sobrien 20590284Sobrien return (retval); 20690284Sobrien} 20790284Sobrien 208169705Skanint 209169705Skanctl_port_deregister(struct ctl_port *port) 21090284Sobrien{ 21190284Sobrien struct ctl_softc *softc = control_softc; 21290284Sobrien struct ctl_io_pool *pool; 21390284Sobrien int port_num, retval, i; 21490284Sobrien 21590284Sobrien retval = 0; 21690284Sobrien 21790284Sobrien pool = (struct ctl_io_pool *)port->ctl_pool_ref; 21890284Sobrien 21990284Sobrien if (port->targ_port == -1) { 22090284Sobrien retval = 1; 22190284Sobrien goto bailout; 22290284Sobrien } 223132743Skan 224169705Skan mtx_lock(&softc->ctl_lock); 225169705Skan STAILQ_REMOVE(&softc->port_list, port, ctl_port, links); 226169705Skan STAILQ_REMOVE(&port->frontend->port_list, port, ctl_port, fe_links); 227169705Skan softc->num_ports--; 228169705Skan port_num = (port->targ_port < CTL_MAX_PORTS) ? port->targ_port : 229169705Skan port->targ_port - CTL_MAX_PORTS; 23051411Sobrien ctl_clear_mask(softc->ctl_port_mask, port_num); 23151411Sobrien softc->ctl_ports[port_num] = NULL; 232117408Skan mtx_unlock(&softc->ctl_lock); 23351411Sobrien 234169705Skan ctl_pool_free(pool); 235169705Skan ctl_free_opts(&port->options); 236169705Skan 237169705Skan ctl_lun_map_deinit(port); 238169705Skan free(port->port_devid, M_CTL); 239169705Skan port->port_devid = NULL; 240169705Skan free(port->target_devid, M_CTL); 241169705Skan port->target_devid = NULL; 242169705Skan free(port->init_devid, M_CTL); 24351411Sobrien port->init_devid = NULL; 244169705Skan for (i = 0; i < port->max_initiators; i++) 245169705Skan free(port->wwpn_iid[i].name, M_CTL); 246169705Skan free(port->wwpn_iid, M_CTL); 247169705Skan 248169705Skanbailout: 249169705Skan return (retval); 250169705Skan} 25190284Sobrien 25290284Sobrienvoid 25390284Sobrienctl_port_set_wwns(struct ctl_port *port, int wwnn_valid, uint64_t wwnn, 25490284Sobrien int wwpn_valid, uint64_t wwpn) 25590284Sobrien{ 25690284Sobrien struct scsi_vpd_id_descriptor *desc; 25790284Sobrien int len, proto; 25890284Sobrien 25990284Sobrien if (port->port_type == CTL_PORT_FC) 26090284Sobrien proto = SCSI_PROTO_FC << 4; 261169705Skan else if (port->port_type == CTL_PORT_ISCSI) 262169705Skan proto = SCSI_PROTO_ISCSI << 4; 26390284Sobrien else 26490284Sobrien proto = SCSI_PROTO_SPI << 4; 26590284Sobrien 26690284Sobrien if (wwnn_valid) { 26790284Sobrien port->wwnn = wwnn; 26890284Sobrien 26990284Sobrien free(port->target_devid, M_CTL); 27090284Sobrien 27190284Sobrien len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN; 27290284Sobrien port->target_devid = malloc(sizeof(struct ctl_devid) + len, 27390284Sobrien M_CTL, M_WAITOK | M_ZERO); 27490284Sobrien port->target_devid->len = len; 27590284Sobrien desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data; 276132743Skan desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY; 277169705Skan desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET | 278169705Skan SVPD_ID_TYPE_NAA; 279169705Skan desc->length = CTL_WWPN_LEN; 280169705Skan scsi_u64to8b(port->wwnn, desc->identifier); 281169705Skan } 282169705Skan 28351411Sobrien if (wwpn_valid) { 28451411Sobrien port->wwpn = wwpn; 285117408Skan 28651411Sobrien free(port->port_devid, M_CTL); 287169705Skan 288169705Skan len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN; 289169705Skan port->port_devid = malloc(sizeof(struct ctl_devid) + len, 290169705Skan M_CTL, M_WAITOK | M_ZERO); 291169705Skan port->port_devid->len = len; 292169705Skan desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data; 293169705Skan desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY; 294169705Skan desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | 295169705Skan SVPD_ID_TYPE_NAA; 29651411Sobrien desc->length = CTL_WWPN_LEN; 297169705Skan scsi_u64to8b(port->wwpn, desc->identifier); 298169705Skan } 299169705Skan} 300169705Skan 301169705Skanvoid 302169705Skanctl_port_online(struct ctl_port *port) 303169705Skan{ 30490284Sobrien struct ctl_softc *softc = control_softc; 30590284Sobrien struct ctl_lun *lun; 30690284Sobrien uint32_t l; 30790284Sobrien 30890284Sobrien if (port->lun_map) { 30990284Sobrien for (l = 0; l < CTL_MAX_LUNS; l++) { 31090284Sobrien if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS) 31190284Sobrien continue; 31290284Sobrien port->lun_enable(port->targ_lun_arg, l); 31390284Sobrien } 314169705Skan } else { 315169705Skan STAILQ_FOREACH(lun, &softc->lun_list, links) 31690284Sobrien port->lun_enable(port->targ_lun_arg, lun->lun); 31790284Sobrien } 31890284Sobrien port->port_online(port->onoff_arg); 31990284Sobrien /* XXX KDM need a lock here? */ 32090284Sobrien port->status |= CTL_PORT_STATUS_ONLINE; 32190284Sobrien} 32290284Sobrien 32390284Sobrienvoid 32490284Sobrienctl_port_offline(struct ctl_port *port) 32590284Sobrien{ 32690284Sobrien struct ctl_softc *softc = control_softc; 32790284Sobrien struct ctl_lun *lun; 32890284Sobrien uint32_t l; 329132743Skan 330169705Skan port->port_offline(port->onoff_arg); 331169705Skan if (port->lun_map) { 332169705Skan for (l = 0; l < CTL_MAX_LUNS; l++) { 333169705Skan if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS) 334169705Skan continue; 335169705Skan port->lun_disable(port->targ_lun_arg, l); 33651411Sobrien } 33751411Sobrien } else { 338117408Skan STAILQ_FOREACH(lun, &softc->lun_list, links) 339219374Smm port->lun_disable(port->targ_lun_arg, lun->lun); 340219374Smm } 341219374Smm /* XXX KDM need a lock here? */ 342219374Smm port->status &= ~CTL_PORT_STATUS_ONLINE; 343219374Smm} 344219374Smm 345219374Smm/* 346219374Smm * vim: ts=8 347219374Smm */ 348219374Smm