From owner-svn-src-projects@FreeBSD.ORG Mon Jul 18 19:26:16 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BECF4106566C; Mon, 18 Jul 2011 19:26:16 +0000 (UTC) (envelope-from gibbs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id AA3FD8FC08; Mon, 18 Jul 2011 19:26:16 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p6IJQG4X036166; Mon, 18 Jul 2011 19:26:16 GMT (envelope-from gibbs@svn.freebsd.org) Received: (from gibbs@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p6IJQG5W036152; Mon, 18 Jul 2011 19:26:16 GMT (envelope-from gibbs@svn.freebsd.org) Message-Id: <201107181926.p6IJQG5W036152@svn.freebsd.org> From: "Justin T. Gibbs" Date: Mon, 18 Jul 2011 19:26:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r224197 - in projects/zfsd/head: share/examples/ses share/examples/ses/srcs sys/amd64/conf sys/cam/scsi sys/conf sys/i386/conf sys/ia64/conf sys/mips/conf sys/modules/cam sys/pc98/conf ... X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Jul 2011 19:26:16 -0000 Author: gibbs Date: Mon Jul 18 19:26:16 2011 New Revision: 224197 URL: http://svn.freebsd.org/changeset/base/224197 Log: Revamp the CAM enclosure services driver, renaming it to "enc" from "ses" in the process. This updated driver uses an in-kernel daemon to track state changes and publishes physical path location information for disk elements into the CAM device database. share/examples/ses/Makefile.inc: share/examples/ses/srcs/eltsub.c: share/examples/ses/srcs/sesd.c: share/examples/ses/srcs/getencstat.c: share/examples/ses/srcs/setobjstat.c: share/examples/ses/srcs/inienc.c: share/examples/ses/srcs/getobjstat.c: share/examples/ses/srcs/getnobj.c: share/examples/ses/srcs/getobjmap.c: share/examples/ses/srcs/setencstat.c: Update for changes in driver name and API. The ioctl interface is largely unchanged and could use additional refinement. It would be nice to be able to fetch the status of all elements in a single ioctl call and to have the ioctls that return variable length data allow you to query the necessary allocation size by passing in a zero length buffer. sys/sparc64/conf/GENERIC: sys/ia64/conf/GENERIC: sys/mips/conf/OCTEON1: sys/pc98/conf/GENERIC: sys/i386/conf/GENERIC: sys/amd64/conf/GENERIC: ses -> enc sys/conf/files: sys/modules/cam/Makefile: sys/cam/scsi/scsi_enc_internal.h sys/cam/scsi/scsi_enc_ses.c sys/cam/scsi/scsi_enc_safte.c sys/cam/scsi/scsi_ses.c sys/cam/scsi/scsi_enc.c Split the enc driver into a generic driver file and one file each for the SES and SAF-TE personalities. sys/cam/scsi/scsi_ses.h: o Retain this header, but use it to only hold structures derived from the T10 SES spec. The driver interface can be found in scsi_enc.h. o Add definitions for most SES pages. sys/cam/scsi/scsi_enc.c sys/cam/scsi/scsi_enc.h o Use a function vector table to allow interaction between the generic and protocol specific portions of this driver. o Provide a generic mechanism allowing personalities to define a finite state machine that is executed from a daemon thread context. o Track CAM device arrival events and pass these on to personalities that have registered an interest in them. These notifications are used to trigger physical path updates in the CAM EDT. sys/cam/scsi/scsi_enc_safte.c: The SAF-TE personality. This module is largely untouched by this update. To achieve the same level of support as we have for SES, it will need to define an FSM and code to determine the physical paths of elements within the enclosure. sys/cam/scsi/scsi_enc_ses.c: o Implement a state machine to fetch configuration, status, element descriptors, and additional element status. o Build a "element map" that indexes into the config and status data retrieved from a SES device. Use this to simplify our responses to ioctls. o Add support for using SAS domain/phy WWN data to determine the physical path (ence@/type@/slot@) of an element. Stubs are in place for FC, but both FC and SPI will need additional work in order to be supported. Sponsored by: Spectra Logic Corporation Submitted by: gibbs, will Added: projects/zfsd/head/sys/cam/scsi/scsi_enc.c projects/zfsd/head/sys/cam/scsi/scsi_enc.h projects/zfsd/head/sys/cam/scsi/scsi_enc_internal.h projects/zfsd/head/sys/cam/scsi/scsi_enc_safte.c projects/zfsd/head/sys/cam/scsi/scsi_enc_ses.c Deleted: projects/zfsd/head/sys/cam/scsi/scsi_ses.c Modified: projects/zfsd/head/share/examples/ses/Makefile.inc projects/zfsd/head/share/examples/ses/srcs/eltsub.c projects/zfsd/head/share/examples/ses/srcs/getencstat.c projects/zfsd/head/share/examples/ses/srcs/getnobj.c projects/zfsd/head/share/examples/ses/srcs/getobjmap.c projects/zfsd/head/share/examples/ses/srcs/getobjstat.c projects/zfsd/head/share/examples/ses/srcs/inienc.c projects/zfsd/head/share/examples/ses/srcs/sesd.c projects/zfsd/head/share/examples/ses/srcs/setencstat.c projects/zfsd/head/share/examples/ses/srcs/setobjstat.c projects/zfsd/head/sys/amd64/conf/GENERIC projects/zfsd/head/sys/cam/scsi/scsi_ses.h projects/zfsd/head/sys/conf/files projects/zfsd/head/sys/i386/conf/GENERIC projects/zfsd/head/sys/ia64/conf/GENERIC projects/zfsd/head/sys/mips/conf/OCTEON1 projects/zfsd/head/sys/modules/cam/Makefile projects/zfsd/head/sys/pc98/conf/GENERIC projects/zfsd/head/sys/sparc64/conf/GENERIC Modified: projects/zfsd/head/share/examples/ses/Makefile.inc ============================================================================== --- projects/zfsd/head/share/examples/ses/Makefile.inc Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/Makefile.inc Mon Jul 18 19:26:16 2011 (r224197) @@ -32,7 +32,6 @@ # mjacob@feral.com # -CFLAGS+= -I/usr/include/cam/scsi -DSESINC="" BINDIR?= /usr/sbin CLEANFILES+= ${MAN} Modified: projects/zfsd/head/share/examples/ses/srcs/eltsub.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/eltsub.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/eltsub.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,10 +33,13 @@ */ #include +#include +#include #include #include #include -#include SESINC +#include +#include #include "eltsub.h" @@ -46,80 +49,83 @@ geteltnm(int type) static char rbuf[132]; switch (type) { - case SESTYP_UNSPECIFIED: + case ELMTYP_UNSPECIFIED: sprintf(rbuf, "Unspecified"); break; - case SESTYP_DEVICE: + case ELMTYP_DEVICE: sprintf(rbuf, "Device"); break; - case SESTYP_POWER: + case ELMTYP_POWER: sprintf(rbuf, "Power supply"); break; - case SESTYP_FAN: + case ELMTYP_FAN: sprintf(rbuf, "Cooling element"); break; - case SESTYP_THERM: + case ELMTYP_THERM: sprintf(rbuf, "Temperature sensors"); break; - case SESTYP_DOORLOCK: + case ELMTYP_DOORLOCK: sprintf(rbuf, "Door Lock"); break; - case SESTYP_ALARM: + case ELMTYP_ALARM: sprintf(rbuf, "Audible alarm"); break; - case SESTYP_ESCC: + case ELMTYP_ESCC: sprintf(rbuf, "Enclosure services controller electronics"); break; - case SESTYP_SCC: + case ELMTYP_SCC: sprintf(rbuf, "SCC controller electronics"); break; - case SESTYP_NVRAM: + case ELMTYP_NVRAM: sprintf(rbuf, "Nonvolatile cache"); break; - case SESTYP_UPS: + case ELMTYP_INV_OP_REASON: + sprintf(rbuf, "Invalid Operation Reason"); + break; + case ELMTYP_UPS: sprintf(rbuf, "Uninterruptible power supply"); break; - case SESTYP_DISPLAY: + case ELMTYP_DISPLAY: sprintf(rbuf, "Display"); break; - case SESTYP_KEYPAD: + case ELMTYP_KEYPAD: sprintf(rbuf, "Key pad entry device"); break; - case SESTYP_ENCLOSURE: + case ELMTYP_ENCLOSURE: sprintf(rbuf, "Enclosure"); break; - case SESTYP_SCSIXVR: + case ELMTYP_SCSIXVR: sprintf(rbuf, "SCSI port/transceiver"); break; - case SESTYP_LANGUAGE: + case ELMTYP_LANGUAGE: sprintf(rbuf, "Language"); break; - case SESTYP_COMPORT: + case ELMTYP_COMPORT: sprintf(rbuf, "Communication Port"); break; - case SESTYP_VOM: + case ELMTYP_VOM: sprintf(rbuf, "Voltage Sensor"); break; - case SESTYP_AMMETER: + case ELMTYP_AMMETER: sprintf(rbuf, "Current Sensor"); break; - case SESTYP_SCSI_TGT: + case ELMTYP_SCSI_TGT: sprintf(rbuf, "SCSI target port"); break; - case SESTYP_SCSI_INI: + case ELMTYP_SCSI_INI: sprintf(rbuf, "SCSI initiator port"); break; - case SESTYP_SUBENC: + case ELMTYP_SUBENC: sprintf(rbuf, "Simple sub-enclosure"); break; - case SESTYP_ARRAY: + case ELMTYP_ARRAY_DEV: sprintf(rbuf, "Array device"); break; - case SESTYP_SASEXPANDER: - sprintf(rbuf, "SAS Expander"); + case ELMTYP_SAS_EXP: + sprintf(rbuf, "SAS expander"); break; - case SESTYP_SASCONNECTOR: - sprintf(rbuf, "SAS Connector"); + case ELMTYP_SAS_CONN: + sprintf(rbuf, "SAS connector"); break; default: (void) sprintf(rbuf, "", type); Modified: projects/zfsd/head/share/examples/ses/srcs/getencstat.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/getencstat.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/getencstat.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,20 +33,25 @@ */ #include +#include +#include #include #include #include #include #include -#include SESINC +#include +#include #include "eltsub.h" int main(int a, char **v) { - ses_object *objp; - ses_objstat ob; + encioc_element_t *objp; + encioc_elm_status_t ob; + encioc_elm_desc_t objd; + encioc_elm_devnames_t objdn; int fd, nobj, f, i, verbose, quiet, errors; u_char estat; @@ -73,13 +78,13 @@ main(int a, char **v) perror(*v); continue; } - if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t) &nobj) < 0) { - perror("SESIOC_GETNOBJ"); + if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { + perror("ENCIOC_GETNELM"); (void) close(fd); continue; } - if (ioctl(fd, SESIOC_GETENCSTAT, (caddr_t) &estat) < 0) { - perror("SESIOC_GETENCSTAT"); + if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) { + perror("ENCIOC_GETENCSTAT"); (void) close(fd); continue; } @@ -113,38 +118,67 @@ main(int a, char **v) } } fprintf(stdout, ">\n"); - objp = calloc(nobj, sizeof (ses_object)); + objp = calloc(nobj, sizeof (encioc_element_t)); if (objp == NULL) { perror("calloc"); (void) close(fd); continue; } - if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t) objp) < 0) { - perror("SESIOC_GETOBJMAP"); + if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) { + perror("ENCIOC_GETELMMAP"); (void) close(fd); continue; } for (i = 0; i < nobj; i++) { - ob.obj_id = objp[i].obj_id; - if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t) &ob) < 0) { - perror("SESIOC_GETOBJSTAT"); + ob.elm_idx = objp[i].elm_idx; + if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &ob) < 0) { + perror("ENCIOC_GETELMSTAT"); (void) close(fd); break; } - if ((ob.cstat[0] & 0xf) == SES_OBJSTAT_OK) { - if (verbose) { - fprintf(stdout, - "Element 0x%x: %s OK (%s)\n", - ob.obj_id, - geteltnm(objp[i].object_type), - stat2ascii(objp[i].object_type, - ob.cstat)); - } + bzero(&objd, sizeof(objd)); + objd.elm_idx = objp[i].elm_idx; + objd.elm_desc_len = UINT16_MAX; + objd.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); + if (objd.elm_desc_str == NULL) { + perror("calloc"); + (void) close(fd); continue; } - fprintf(stdout, "Element 0x%x: %s, %s\n", - ob.obj_id, geteltnm(objp[i].object_type), - stat2ascii(objp[i].object_type, ob.cstat)); + if (ioctl(fd, ENCIOC_GETELMDESC, (caddr_t)&objd) < 0) { + perror("ENCIOC_GETELMDESC"); + (void) close(fd); + break; + } + bzero(&objdn, sizeof(objdn)); + objdn.elm_idx = objp[i].elm_idx; + objdn.elm_names_size = 128; + objdn.elm_devnames = calloc(128, sizeof(char)); + if (objdn.elm_devnames == NULL) { + perror("calloc"); + (void) close(fd); + break; + } + /* + * This ioctl isn't critical and has a good chance + * of returning -1. + */ + (void)ioctl(fd, ENCIOC_GETELMDEVNAMES, (caddr_t)&objdn); + fprintf(stdout, "Element 0x%x: %s", ob.elm_idx, + geteltnm(objp[i].elm_type)); + if ((ob.cstat[0] & 0xf) == SES_OBJSTAT_OK) + fprintf(stdout, ", OK (%s)", + stat2ascii(objp[i].elm_type, ob.cstat)); + else + fprintf(stdout, ", %s", + stat2ascii(objp[i].elm_type, ob.cstat)); + fprintf(stdout, ", descriptor: '%s'", + objd.elm_desc_str); + if (objdn.elm_names_len > 0) + fprintf(stdout, ", dev: '%s'", + objdn.elm_devnames); + fprintf(stdout, "\n"); + free(objdn.elm_devnames); } free(objp); (void) close(fd); Modified: projects/zfsd/head/share/examples/ses/srcs/getnobj.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/getnobj.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/getnobj.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,12 +33,15 @@ */ #include +#include +#include #include #include #include #include #include -#include SESINC +#include +#include int main(int argc, char **argv) Modified: projects/zfsd/head/share/examples/ses/srcs/getobjmap.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/getobjmap.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/getobjmap.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,11 +33,14 @@ */ #include +#include +#include #include #include #include #include -#include SESINC +#include +#include #include "eltsub.h" Modified: projects/zfsd/head/share/examples/ses/srcs/getobjstat.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/getobjstat.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/getobjstat.c Mon Jul 18 19:26:16 2011 (r224197) @@ -32,11 +32,14 @@ * mjacob@feral.com */ #include +#include +#include #include #include #include #include -#include SESINC +#include +#include int main(int a, char **v) Modified: projects/zfsd/head/share/examples/ses/srcs/inienc.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/inienc.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/inienc.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,11 +33,14 @@ */ #include +#include +#include #include #include #include #include -#include SESINC +#include +#include int main(int a, char **v) Modified: projects/zfsd/head/share/examples/ses/srcs/sesd.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/sesd.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/sesd.c Mon Jul 18 19:26:16 2011 (r224197) @@ -32,6 +32,8 @@ * mjacob@feral.com */ #include +#include +#include #include #include #include @@ -39,7 +41,8 @@ #include #include #include -#include SESINC +#include +#include #define ALLSTAT (SES_ENCSTAT_UNRECOV | SES_ENCSTAT_CRITICAL | \ SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) @@ -54,7 +57,7 @@ main(int a, char **v) static const char *usage = "usage: %s [ -d ] [ -t pollinterval ] device [ device ]\n"; int fd, polltime, dev, devbase, nodaemon; - ses_encstat stat, *carray; + encioc_enc_status_t stat, *carray; if (a < 2) { fprintf(stderr, usage, *v); @@ -83,7 +86,7 @@ main(int a, char **v) return (1); } for (dev = devbase; dev < a; dev++) - carray[dev] = (ses_encstat) -1; + carray[dev] = (encioc_enc_status_t) -1; /* * Check to make sure we can open all devices @@ -94,8 +97,8 @@ main(int a, char **v) perror(v[dev]); return (1); } - if (ioctl(fd, SESIOC_INIT, NULL) < 0) { - fprintf(stderr, "%s: SESIOC_INIT fails- %s\n", + if (ioctl(fd, ENCIOC_INIT, NULL) < 0) { + fprintf(stderr, "%s: ENCIOC_INIT fails- %s\n", v[dev], strerror(errno)); return (1); } @@ -122,9 +125,9 @@ main(int a, char **v) /* * Get the actual current enclosure status. */ - if (ioctl(fd, SESIOC_GETENCSTAT, (caddr_t) &stat) < 0) { + if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &stat) < 0) { syslog(LOG_ERR, - "%s: SESIOC_GETENCSTAT- %m", v[dev]); + "%s: ENCIOC_GETENCSTAT- %m", v[dev]); (void) close(fd); continue; } Modified: projects/zfsd/head/share/examples/ses/srcs/setencstat.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/setencstat.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/setencstat.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,18 +33,21 @@ */ #include +#include +#include #include #include #include #include -#include SESINC +#include +#include int main(int a, char **v) { int fd; long val; - ses_encstat stat; + encioc_enc_status_t stat; if (a != 3) { fprintf(stderr, "usage: %s device enclosure_status\n", *v); @@ -57,9 +60,9 @@ main(int a, char **v) } val = strtol(v[2], NULL, 0); - stat = (ses_encstat) val; - if (ioctl(fd, SESIOC_SETENCSTAT, (caddr_t) &stat) < 0) { - perror("SESIOC_SETENCSTAT"); + stat = (encioc_enc_status_t)val; + if (ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &stat) < 0) { + perror("ENCIOC_SETENCSTAT"); } (void) close(fd); return (0); Modified: projects/zfsd/head/share/examples/ses/srcs/setobjstat.c ============================================================================== --- projects/zfsd/head/share/examples/ses/srcs/setobjstat.c Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/share/examples/ses/srcs/setobjstat.c Mon Jul 18 19:26:16 2011 (r224197) @@ -33,18 +33,21 @@ */ #include +#include +#include #include #include #include #include -#include SESINC +#include +#include int main(int a, char **v) { int fd; int i; - ses_objstat obj; + encioc_elm_status_t obj; long cvt; char *x; @@ -64,7 +67,7 @@ usage: if (x == v[2]) { goto usage; } - obj.obj_id = cvt; + obj.elm_idx = cvt; for (i = 0; i < 4; i++) { x = v[3 + i]; cvt = strtol(v[3 + i], &x, 0); @@ -73,8 +76,8 @@ usage: } obj.cstat[i] = cvt; } - if (ioctl(fd, SESIOC_SETOBJSTAT, (caddr_t) &obj) < 0) { - perror("SESIOC_SETOBJSTAT"); + if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &obj) < 0) { + perror("ENCIOC_SETELMSTAT"); } (void) close(fd); return (0); Modified: projects/zfsd/head/sys/amd64/conf/GENERIC ============================================================================== --- projects/zfsd/head/sys/amd64/conf/GENERIC Mon Jul 18 19:23:50 2011 (r224196) +++ projects/zfsd/head/sys/amd64/conf/GENERIC Mon Jul 18 19:26:16 2011 (r224197) @@ -126,7 +126,7 @@ device da # Direct Access (disks) device sa # Sequential Access (tape etc) device cd # CD device pass # Passthrough device (direct ATA/SCSI access) -device ses # SCSI Environmental Services (and SAF-TE) +device enc # Enclosure Services (SES and SAF-TE) # RAID controllers interfaced to the SCSI subsystem device amr # AMI MegaRAID Added: projects/zfsd/head/sys/cam/scsi/scsi_enc.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/zfsd/head/sys/cam/scsi/scsi_enc.c Mon Jul 18 19:26:16 2011 (r224197) @@ -0,0 +1,975 @@ +/*- + * Copyright (c) 2000 Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers"); + +/* Enclosure type independent driver */ + +#define SEN_ID "UNISYS SUN_SEN" +#define SEN_ID_LEN 24 + +static d_open_t enc_open; +static d_close_t enc_close; +static d_ioctl_t enc_ioctl; +static periph_init_t enc_init; +static periph_ctor_t enc_ctor; +static periph_oninv_t enc_oninvalidate; +static periph_dtor_t enc_dtor; +static periph_start_t enc_start; + +static void enc_async(void *, uint32_t, struct cam_path *, void *); +static enctyp enc_type(void *, int); + +static struct periph_driver encdriver = { + enc_init, "enc", + TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 +}; + +PERIPHDRIVER_DECLARE(enc, encdriver); + +static struct cdevsw enc_cdevsw = { + .d_version = D_VERSION, + .d_open = enc_open, + .d_close = enc_close, + .d_ioctl = enc_ioctl, + .d_name = "enc", + .d_flags = 0, +}; + +static void +enc_init(void) +{ + cam_status status; + + /* + * Install a global async callback. This callback will + * receive async callbacks like "new device found". + */ + status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL); + + if (status != CAM_REQ_CMP) { + printf("enc: Failed to attach master async callback " + "due to status 0x%x!\n", status); + } +} + +static void +enc_oninvalidate(struct cam_periph *periph) +{ + struct enc_softc *enc; + + enc = periph->softc; + + /* If the sub-driver has an invalidate routine, call it */ + if (enc->enc_vec.softc_invalidate != NULL) + enc->enc_vec.softc_invalidate(periph); + + /* + * Unregister any async callbacks. + */ + xpt_register_async(0, enc_async, periph, periph->path); + + /* + * Shutdown our daemon. + */ + enc->enc_flags |= ENC_FLAG_SHUTDOWN; + if (enc->enc_daemon != NULL) { + /* Signal and wait for the ses daemon to terminate. */ + wakeup(enc->enc_daemon); + /* + * We're called with the SIM mutex held, but we're dropping + * the update mutex here on sleep. So we have to manually + * drop the SIM mutex. + */ + cam_periph_sleep(enc->periph, enc->enc_daemon, + PUSER, "thtrm", 0); + } + callout_drain(&enc->status_updater); + + enc->enc_flags |= ENC_FLAG_INVALID; + + xpt_print(periph->path, "lost device\n"); +} + +static void +enc_dtor(struct cam_periph *periph) +{ + struct enc_softc *enc; + + enc = periph->softc; + + xpt_print(periph->path, "removing device entry\n"); + cam_periph_unlock(periph); + destroy_dev(enc->enc_dev); + cam_periph_lock(periph); + + /* If the sub-driver has a cleanup routine, call it */ + if (enc->enc_vec.softc_cleanup != NULL) + enc->enc_vec.softc_cleanup(periph); + + if (enc->enc_boot_hold_ch.ich_func != NULL) { + config_intrhook_disestablish(&enc->enc_boot_hold_ch); + enc->enc_boot_hold_ch.ich_func = NULL; + } + + ENC_FREE(enc); +} + +static void +enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) +{ + struct cam_periph *periph; + + periph = (struct cam_periph *)callback_arg; + + switch(code) { + case AC_FOUND_DEVICE: + { + struct ccb_getdev *cgd; + cam_status status; + int inq_len; + path_id_t path_id; + + cgd = (struct ccb_getdev *)arg; + if (arg == NULL) { + break; + } + + if (cgd->protocol != PROTO_SCSI) + break; + + inq_len = cgd->inq_data.additional_length + 4; + + /* + * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS + * PROBLEM: IS A SAF-TE DEVICE. + */ + switch (enc_type(&cgd->inq_data, inq_len)) { + case ENC_SES: + case ENC_SES_SCSI2: + case ENC_SES_PASSTHROUGH: + case ENC_SEN: + case ENC_SAFT: + break; + default: + /* + * Schedule announcement of the ENC bindings for + * this device if it is managed by a SEP. + */ + path_id = xpt_path_path_id(path); + xpt_lock_buses(); + TAILQ_FOREACH(periph, &encdriver.units, unit_links) { + struct enc_softc *softc; + + softc = (struct enc_softc *)periph->softc; + if (xpt_path_path_id(periph->path) != path_id + || softc == NULL + || (softc->enc_flags & ENC_FLAG_INITIALIZED) + == 0 + || softc->enc_vec.device_found == NULL) + continue; + + softc->enc_vec.device_found(softc); + } + xpt_unlock_buses(); + return; + } + + status = cam_periph_alloc(enc_ctor, enc_oninvalidate, + enc_dtor, enc_start, "enc", CAM_PERIPH_BIO, + cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd); + + if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) { + printf("enc_async: Unable to probe new device due to " + "status 0x%x\n", status); + } + break; + } + default: + cam_periph_async(periph, code, path, arg); + break; + } +} + +static int +enc_open(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + struct cam_periph *periph; + struct enc_softc *softc; + int error = 0; + + periph = (struct cam_periph *)dev->si_drv1; + if (periph == NULL) { + return (ENXIO); + } + + if (cam_periph_acquire(periph) != CAM_REQ_CMP) { + cam_periph_unlock(periph); + return (ENXIO); + } + + cam_periph_lock(periph); + + softc = (struct enc_softc *)periph->softc; + + if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { + error = ENXIO; + goto out; + } + if (softc->enc_flags & ENC_FLAG_INVALID) { + error = ENXIO; + goto out; + } + +out: + cam_periph_unlock(periph); + if (error) { + cam_periph_release(periph); + } + return (error); +} + +static int +enc_close(struct cdev *dev, int flag, int fmt, struct thread *td) +{ + struct cam_periph *periph; + struct enc_softc *softc; + int error; + + error = 0; + + periph = (struct cam_periph *)dev->si_drv1; + if (periph == NULL) + return (ENXIO); + + cam_periph_lock(periph); + + softc = (struct enc_softc *)periph->softc; + + cam_periph_unlock(periph); + cam_periph_release(periph); + + return (0); +} + +static void +enc_start(struct cam_periph *p, union ccb *sccb) +{ + struct enc_softc *enc; + + enc = p->softc; + ENC_DLOG(enc, "%s enter imm=%d prio=%d\n", + __func__, p->immediate_priority, p->pinfo.priority); + if (p->immediate_priority <= p->pinfo.priority) { + SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle); + p->immediate_priority = CAM_PRIORITY_NONE; + wakeup(&p->ccb_list); + } else + xpt_release_ccb(sccb); + ENC_DLOG(enc, "%s exit\n", __func__); +} + +void +enc_done(struct cam_periph *periph, union ccb *dccb) +{ + wakeup(&dccb->ccb_h.cbfcnp); +} + +int +enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags) +{ + struct enc_softc *softc; + struct cam_periph *periph; + + periph = xpt_path_periph(ccb->ccb_h.path); + softc = (struct enc_softc *)periph->softc; + + return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb)); +} + +static int +enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, + struct thread *td) +{ + struct cam_periph *periph; + encioc_enc_status_t tmp; + encioc_string_t sstr; + encioc_elm_status_t elms; + encioc_elm_desc_t elmd; + encioc_elm_devnames_t elmdn; + encioc_element_t *uelm; + enc_softc_t *enc; + enc_cache_t *cache; + void *addr; + int error, i; + + + if (arg_addr) + addr = *((caddr_t *) arg_addr); + else + addr = NULL; + + periph = (struct cam_periph *)dev->si_drv1; + if (periph == NULL) + return (ENXIO); + + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n")); + + cam_periph_lock(periph); + enc = (struct enc_softc *)periph->softc; + cache = &enc->enc_cache; + + /* + * Now check to see whether we're initialized or not. + * This actually should never fail as we're not supposed + * to get past enc_open w/o successfully initializing + * things. + */ + if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { + cam_periph_unlock(periph); + return (ENXIO); + } + cam_periph_unlock(periph); + + error = 0; + + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, + ("trying to do ioctl %#lx\n", cmd)); + + /* + * If this command can change the device's state, + * we must have the device open for writing. + * + * For commands that get information about the + * device- we don't need to lock the peripheral + * if we aren't running a command. The periph + * also can't go away while a user process has + * it open. + */ + switch (cmd) { + case ENCIOC_GETNELM: + case ENCIOC_GETELMMAP: + case ENCIOC_GETENCSTAT: + case ENCIOC_GETELMSTAT: + case ENCIOC_GETELMDESC: + case ENCIOC_GETELMDEVNAMES: + break; + default: + if ((flag & FWRITE) == 0) { + return (EBADF); + } + } + + /* + * XXX The values read here are only valid for the current + * configuration generation. We need these ioctls + * to also pass in/out a generation number. + */ + sx_slock(&enc->enc_cache_lock); + switch (cmd) { + case ENCIOC_GETNELM: + error = copyout(&cache->nelms, addr, sizeof (cache->nelms)); + break; + + case ENCIOC_GETELMMAP: + for (uelm = addr, i = 0; i != cache->nelms; i++) { + encioc_element_t kelm; + kelm.elm_idx = i; + kelm.elm_subenc_id = cache->elm_map[i].subenclosure; + kelm.elm_type = cache->elm_map[i].enctype; + error = copyout(&kelm, &uelm[i], sizeof(kelm)); + if (error) + break; + } + break; + + case ENCIOC_GETENCSTAT: + cam_periph_lock(periph); + error = enc->enc_vec.get_enc_status(enc, 1); + if (error) { + cam_periph_unlock(periph); + break; + } + tmp = cache->enc_status & ~ENCI_SVALID; + cam_periph_unlock(periph); + error = copyout(&tmp, addr, sizeof(tmp)); + cache->enc_status = tmp; + break; + + case ENCIOC_SETENCSTAT: + error = copyin(addr, &tmp, sizeof(tmp)); + if (error) + break; + cam_periph_lock(periph); + error = enc->enc_vec.set_enc_status(enc, tmp, 1); + cam_periph_unlock(periph); + break; + + case ENCIOC_GETSTRING: + case ENCIOC_SETSTRING: + if (enc->enc_vec.handle_string == NULL) { + error = EINVAL; + break; + } + error = copyin(addr, &sstr, sizeof(sstr)); + if (error) + break; + cam_periph_lock(periph); + error = enc->enc_vec.handle_string(enc, &sstr, cmd); + cam_periph_unlock(periph); + break; + + case ENCIOC_GETELMSTAT: + error = copyin(addr, &elms, sizeof(elms)); + if (error) + break; + if (elms.elm_idx >= cache->nelms) { + error = EINVAL; + break; + } + cam_periph_lock(periph); + error = enc->enc_vec.get_elm_status(enc, &elms, 1); + cam_periph_unlock(periph); + if (error) + break; + error = copyout(&elms, addr, sizeof(elms)); + break; + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***