1*24db4641Seschrock /* 2*24db4641Seschrock * CDDL HEADER START 3*24db4641Seschrock * 4*24db4641Seschrock * The contents of this file are subject to the terms of the 5*24db4641Seschrock * Common Development and Distribution License (the "License"). 6*24db4641Seschrock * You may not use this file except in compliance with the License. 7*24db4641Seschrock * 8*24db4641Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*24db4641Seschrock * or http://www.opensolaris.org/os/licensing. 10*24db4641Seschrock * See the License for the specific language governing permissions 11*24db4641Seschrock * and limitations under the License. 12*24db4641Seschrock * 13*24db4641Seschrock * When distributing Covered Code, include this CDDL HEADER in each 14*24db4641Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*24db4641Seschrock * If applicable, add the following below this CDDL HEADER, with the 16*24db4641Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 17*24db4641Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*24db4641Seschrock * 19*24db4641Seschrock * CDDL HEADER END 20*24db4641Seschrock */ 21*24db4641Seschrock /* 22*24db4641Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*24db4641Seschrock * Use is subject to license terms. 24*24db4641Seschrock */ 25*24db4641Seschrock 26*24db4641Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 27*24db4641Seschrock 28*24db4641Seschrock /* 29*24db4641Seschrock * Disk status library 30*24db4641Seschrock * 31*24db4641Seschrock * This library is responsible for querying health and other status information 32*24db4641Seschrock * from disk drives. It is intended to be a generic interface, however only 33*24db4641Seschrock * SCSI (and therefore SATA) disks are currently supported. The library is 34*24db4641Seschrock * capable of detecting the following status conditions: 35*24db4641Seschrock * 36*24db4641Seschrock * - Predictive failure 37*24db4641Seschrock * - Overtemp 38*24db4641Seschrock * - Self-test failure 39*24db4641Seschrock */ 40*24db4641Seschrock 41*24db4641Seschrock #include <assert.h> 42*24db4641Seschrock #include <errno.h> 43*24db4641Seschrock #include <fcntl.h> 44*24db4641Seschrock #include <libdevinfo.h> 45*24db4641Seschrock #include <libdiskstatus.h> 46*24db4641Seschrock #include <stdlib.h> 47*24db4641Seschrock #include <string.h> 48*24db4641Seschrock #include <sys/fm/io/scsi.h> 49*24db4641Seschrock #include <sys/stat.h> 50*24db4641Seschrock #include <unistd.h> 51*24db4641Seschrock 52*24db4641Seschrock #include "ds_impl.h" 53*24db4641Seschrock #include "ds_scsi.h" 54*24db4641Seschrock 55*24db4641Seschrock static ds_transport_t *ds_transports[] = { 56*24db4641Seschrock &ds_scsi_sim_transport, 57*24db4641Seschrock &ds_scsi_uscsi_transport 58*24db4641Seschrock }; 59*24db4641Seschrock 60*24db4641Seschrock #define NTRANSPORTS (sizeof (ds_transports) / sizeof (ds_transports[0])) 61*24db4641Seschrock 62*24db4641Seschrock /* 63*24db4641Seschrock * Open a handle to a disk. This will fail if the device cannot be opened, or 64*24db4641Seschrock * if no suitable transport exists for communicating with the device. 65*24db4641Seschrock */ 66*24db4641Seschrock disk_status_t * 67*24db4641Seschrock disk_status_open(const char *path, int *error) 68*24db4641Seschrock { 69*24db4641Seschrock disk_status_t *dsp; 70*24db4641Seschrock ds_transport_t *t; 71*24db4641Seschrock int i; 72*24db4641Seschrock 73*24db4641Seschrock if ((dsp = calloc(sizeof (disk_status_t), 1)) == NULL) { 74*24db4641Seschrock *error = EDS_NOMEM; 75*24db4641Seschrock return (NULL); 76*24db4641Seschrock } 77*24db4641Seschrock 78*24db4641Seschrock if ((dsp->ds_fd = open(path, O_RDWR)) < 0) { 79*24db4641Seschrock *error = EDS_CANT_OPEN; 80*24db4641Seschrock free(dsp); 81*24db4641Seschrock return (NULL); 82*24db4641Seschrock } 83*24db4641Seschrock 84*24db4641Seschrock if ((dsp->ds_path = strdup(path)) == NULL) { 85*24db4641Seschrock *error = EDS_NOMEM; 86*24db4641Seschrock disk_status_close(dsp); 87*24db4641Seschrock return (NULL); 88*24db4641Seschrock } 89*24db4641Seschrock 90*24db4641Seschrock for (i = 0; i < NTRANSPORTS; i++) { 91*24db4641Seschrock t = ds_transports[i]; 92*24db4641Seschrock 93*24db4641Seschrock dsp->ds_transport = t; 94*24db4641Seschrock 95*24db4641Seschrock nvlist_free(dsp->ds_state); 96*24db4641Seschrock dsp->ds_state = NULL; 97*24db4641Seschrock if (nvlist_alloc(&dsp->ds_state, NV_UNIQUE_NAME, 0) != 0) { 98*24db4641Seschrock *error = EDS_NOMEM; 99*24db4641Seschrock disk_status_close(dsp); 100*24db4641Seschrock return (NULL); 101*24db4641Seschrock } 102*24db4641Seschrock 103*24db4641Seschrock if ((dsp->ds_data = t->dt_open(dsp)) == NULL) { 104*24db4641Seschrock if (dsp->ds_error != EDS_NO_TRANSPORT) { 105*24db4641Seschrock *error = dsp->ds_error; 106*24db4641Seschrock disk_status_close(dsp); 107*24db4641Seschrock return (NULL); 108*24db4641Seschrock } 109*24db4641Seschrock } else { 110*24db4641Seschrock dsp->ds_error = 0; 111*24db4641Seschrock break; 112*24db4641Seschrock } 113*24db4641Seschrock } 114*24db4641Seschrock 115*24db4641Seschrock if (dsp->ds_error == EDS_NO_TRANSPORT) { 116*24db4641Seschrock *error = dsp->ds_error; 117*24db4641Seschrock disk_status_close(dsp); 118*24db4641Seschrock return (NULL); 119*24db4641Seschrock } 120*24db4641Seschrock 121*24db4641Seschrock return (dsp); 122*24db4641Seschrock } 123*24db4641Seschrock 124*24db4641Seschrock /* 125*24db4641Seschrock * Close a handle to a disk. 126*24db4641Seschrock */ 127*24db4641Seschrock void 128*24db4641Seschrock disk_status_close(disk_status_t *dsp) 129*24db4641Seschrock { 130*24db4641Seschrock nvlist_free(dsp->ds_state); 131*24db4641Seschrock nvlist_free(dsp->ds_predfail); 132*24db4641Seschrock nvlist_free(dsp->ds_overtemp); 133*24db4641Seschrock nvlist_free(dsp->ds_testfail); 134*24db4641Seschrock if (dsp->ds_data) 135*24db4641Seschrock dsp->ds_transport->dt_close(dsp->ds_data); 136*24db4641Seschrock (void) close(dsp->ds_fd); 137*24db4641Seschrock free(dsp->ds_path); 138*24db4641Seschrock free(dsp); 139*24db4641Seschrock } 140*24db4641Seschrock 141*24db4641Seschrock void 142*24db4641Seschrock disk_status_set_debug(boolean_t value) 143*24db4641Seschrock { 144*24db4641Seschrock ds_debug = value; 145*24db4641Seschrock } 146*24db4641Seschrock 147*24db4641Seschrock /* 148*24db4641Seschrock * Query basic information 149*24db4641Seschrock */ 150*24db4641Seschrock const char * 151*24db4641Seschrock disk_status_path(disk_status_t *dsp) 152*24db4641Seschrock { 153*24db4641Seschrock return (dsp->ds_path); 154*24db4641Seschrock } 155*24db4641Seschrock 156*24db4641Seschrock int 157*24db4641Seschrock disk_status_errno(disk_status_t *dsp) 158*24db4641Seschrock { 159*24db4641Seschrock return (dsp->ds_error); 160*24db4641Seschrock } 161*24db4641Seschrock 162*24db4641Seschrock nvlist_t * 163*24db4641Seschrock disk_status_get(disk_status_t *dsp) 164*24db4641Seschrock { 165*24db4641Seschrock nvlist_t *nvl = NULL; 166*24db4641Seschrock nvlist_t *faults = NULL; 167*24db4641Seschrock int err; 168*24db4641Seschrock 169*24db4641Seschrock /* 170*24db4641Seschrock * Scan (or rescan) the current device. 171*24db4641Seschrock */ 172*24db4641Seschrock nvlist_free(dsp->ds_testfail); 173*24db4641Seschrock nvlist_free(dsp->ds_predfail); 174*24db4641Seschrock nvlist_free(dsp->ds_overtemp); 175*24db4641Seschrock dsp->ds_testfail = dsp->ds_overtemp = dsp->ds_predfail = NULL; 176*24db4641Seschrock dsp->ds_faults = 0; 177*24db4641Seschrock 178*24db4641Seschrock /* 179*24db4641Seschrock * Even if there is an I/O failure when trying to scan the device, we 180*24db4641Seschrock * can still return the current state. 181*24db4641Seschrock */ 182*24db4641Seschrock if (dsp->ds_transport->dt_scan(dsp->ds_data) != 0 && 183*24db4641Seschrock dsp->ds_error != EDS_IO) 184*24db4641Seschrock return (NULL); 185*24db4641Seschrock 186*24db4641Seschrock if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 187*24db4641Seschrock goto nverror; 188*24db4641Seschrock 189*24db4641Seschrock if ((err = nvlist_add_string(nvl, "protocol", "scsi")) != 0 || 190*24db4641Seschrock (err = nvlist_add_nvlist(nvl, "status", dsp->ds_state)) != 0) 191*24db4641Seschrock goto nverror; 192*24db4641Seschrock 193*24db4641Seschrock /* 194*24db4641Seschrock * Construct the list of faults. 195*24db4641Seschrock */ 196*24db4641Seschrock if ((err = nvlist_alloc(&faults, NV_UNIQUE_NAME, 0)) != 0) 197*24db4641Seschrock goto nverror; 198*24db4641Seschrock 199*24db4641Seschrock if (dsp->ds_predfail != NULL) { 200*24db4641Seschrock if ((err = nvlist_add_boolean_value(faults, 201*24db4641Seschrock FM_EREPORT_SCSI_PREDFAIL, 202*24db4641Seschrock (dsp->ds_faults & DS_FAULT_PREDFAIL) != 0)) != 0 || 203*24db4641Seschrock (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_PREDFAIL, 204*24db4641Seschrock dsp->ds_predfail)) != 0) 205*24db4641Seschrock goto nverror; 206*24db4641Seschrock } 207*24db4641Seschrock 208*24db4641Seschrock if (dsp->ds_testfail != NULL) { 209*24db4641Seschrock if ((err = nvlist_add_boolean_value(faults, 210*24db4641Seschrock FM_EREPORT_SCSI_TESTFAIL, 211*24db4641Seschrock (dsp->ds_faults & DS_FAULT_TESTFAIL) != 0)) != 0 || 212*24db4641Seschrock (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_TESTFAIL, 213*24db4641Seschrock dsp->ds_testfail)) != 0) 214*24db4641Seschrock goto nverror; 215*24db4641Seschrock } 216*24db4641Seschrock 217*24db4641Seschrock if (dsp->ds_overtemp != NULL) { 218*24db4641Seschrock if ((err = nvlist_add_boolean_value(faults, 219*24db4641Seschrock FM_EREPORT_SCSI_OVERTEMP, 220*24db4641Seschrock (dsp->ds_faults & DS_FAULT_OVERTEMP) != 0)) != 0 || 221*24db4641Seschrock (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_OVERTEMP, 222*24db4641Seschrock dsp->ds_overtemp)) != 0) 223*24db4641Seschrock goto nverror; 224*24db4641Seschrock } 225*24db4641Seschrock 226*24db4641Seschrock if ((err = nvlist_add_nvlist(nvl, "faults", faults)) != 0) 227*24db4641Seschrock goto nverror; 228*24db4641Seschrock 229*24db4641Seschrock nvlist_free(faults); 230*24db4641Seschrock return (nvl); 231*24db4641Seschrock 232*24db4641Seschrock nverror: 233*24db4641Seschrock assert(err == ENOMEM); 234*24db4641Seschrock nvlist_free(nvl); 235*24db4641Seschrock nvlist_free(faults); 236*24db4641Seschrock (void) ds_set_errno(dsp, EDS_NOMEM); 237*24db4641Seschrock return (NULL); 238*24db4641Seschrock } 239