1*12767SJames.Kremer@Sun.COM /* 2*12767SJames.Kremer@Sun.COM * CDDL HEADER START 3*12767SJames.Kremer@Sun.COM * 4*12767SJames.Kremer@Sun.COM * The contents of this file are subject to the terms of the 5*12767SJames.Kremer@Sun.COM * Common Development and Distribution License (the "License"). 6*12767SJames.Kremer@Sun.COM * You may not use this file except in compliance with the License. 7*12767SJames.Kremer@Sun.COM * 8*12767SJames.Kremer@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*12767SJames.Kremer@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*12767SJames.Kremer@Sun.COM * See the License for the specific language governing permissions 11*12767SJames.Kremer@Sun.COM * and limitations under the License. 12*12767SJames.Kremer@Sun.COM * 13*12767SJames.Kremer@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*12767SJames.Kremer@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*12767SJames.Kremer@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*12767SJames.Kremer@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*12767SJames.Kremer@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*12767SJames.Kremer@Sun.COM * 19*12767SJames.Kremer@Sun.COM * CDDL HEADER END 20*12767SJames.Kremer@Sun.COM */ 21*12767SJames.Kremer@Sun.COM /* 22*12767SJames.Kremer@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23*12767SJames.Kremer@Sun.COM */ 24*12767SJames.Kremer@Sun.COM 25*12767SJames.Kremer@Sun.COM /* 26*12767SJames.Kremer@Sun.COM * SES Log reader library 27*12767SJames.Kremer@Sun.COM * 28*12767SJames.Kremer@Sun.COM * This library is responsible for accessing the SES log at the target address, 29*12767SJames.Kremer@Sun.COM * formatting and returning any log entries found. 30*12767SJames.Kremer@Sun.COM * 31*12767SJames.Kremer@Sun.COM * The data will be returned in an nvlist_t structure allocated here. 32*12767SJames.Kremer@Sun.COM */ 33*12767SJames.Kremer@Sun.COM 34*12767SJames.Kremer@Sun.COM #include <assert.h> 35*12767SJames.Kremer@Sun.COM #include <errno.h> 36*12767SJames.Kremer@Sun.COM #include <fcntl.h> 37*12767SJames.Kremer@Sun.COM #include <sys/param.h> 38*12767SJames.Kremer@Sun.COM #include <libseslog.h> 39*12767SJames.Kremer@Sun.COM #include <stdlib.h> 40*12767SJames.Kremer@Sun.COM #include <string.h> 41*12767SJames.Kremer@Sun.COM #include <sys/stat.h> 42*12767SJames.Kremer@Sun.COM #include <unistd.h> 43*12767SJames.Kremer@Sun.COM #include <dirent.h> 44*12767SJames.Kremer@Sun.COM #include <sys/scsi/generic/commands.h> 45*12767SJames.Kremer@Sun.COM #include <sys/scsi/generic/status.h> 46*12767SJames.Kremer@Sun.COM 47*12767SJames.Kremer@Sun.COM /* 48*12767SJames.Kremer@Sun.COM * open the device with given device name 49*12767SJames.Kremer@Sun.COM */ 50*12767SJames.Kremer@Sun.COM static int 51*12767SJames.Kremer@Sun.COM open_device(const char *device_name) 52*12767SJames.Kremer@Sun.COM { 53*12767SJames.Kremer@Sun.COM int oflags = O_NONBLOCK | O_RDWR; 54*12767SJames.Kremer@Sun.COM int fd; 55*12767SJames.Kremer@Sun.COM 56*12767SJames.Kremer@Sun.COM fd = open(device_name, oflags); 57*12767SJames.Kremer@Sun.COM if (fd < 0) 58*12767SJames.Kremer@Sun.COM fd = -errno; 59*12767SJames.Kremer@Sun.COM return (fd); 60*12767SJames.Kremer@Sun.COM } 61*12767SJames.Kremer@Sun.COM 62*12767SJames.Kremer@Sun.COM /* 63*12767SJames.Kremer@Sun.COM * Initialize scsi struct 64*12767SJames.Kremer@Sun.COM */ 65*12767SJames.Kremer@Sun.COM static void 66*12767SJames.Kremer@Sun.COM construct_scsi_pt_obj(struct uscsi_cmd *uscsi) 67*12767SJames.Kremer@Sun.COM { 68*12767SJames.Kremer@Sun.COM (void) memset(uscsi, 0, sizeof (struct uscsi_cmd)); 69*12767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = DEF_PT_TIMEOUT; 70*12767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; 71*12767SJames.Kremer@Sun.COM } 72*12767SJames.Kremer@Sun.COM 73*12767SJames.Kremer@Sun.COM /* 74*12767SJames.Kremer@Sun.COM * set control cdb of scsi structure 75*12767SJames.Kremer@Sun.COM */ 76*12767SJames.Kremer@Sun.COM static void 77*12767SJames.Kremer@Sun.COM set_scsi_pt_cdb(struct uscsi_cmd *uscsi, const unsigned char *cdb, 78*12767SJames.Kremer@Sun.COM int cdb_len) 79*12767SJames.Kremer@Sun.COM { 80*12767SJames.Kremer@Sun.COM uscsi->uscsi_cdb = (char *)cdb; 81*12767SJames.Kremer@Sun.COM uscsi->uscsi_cdblen = cdb_len; 82*12767SJames.Kremer@Sun.COM } 83*12767SJames.Kremer@Sun.COM 84*12767SJames.Kremer@Sun.COM /* 85*12767SJames.Kremer@Sun.COM * initialize sense data 86*12767SJames.Kremer@Sun.COM */ 87*12767SJames.Kremer@Sun.COM static void 88*12767SJames.Kremer@Sun.COM set_scsi_pt_sense(struct uscsi_cmd *uscsi, unsigned char *sense, 89*12767SJames.Kremer@Sun.COM int max_sense_len) 90*12767SJames.Kremer@Sun.COM { 91*12767SJames.Kremer@Sun.COM (void) memset(sense, 0, max_sense_len); 92*12767SJames.Kremer@Sun.COM uscsi->uscsi_rqbuf = (char *)sense; 93*12767SJames.Kremer@Sun.COM uscsi->uscsi_rqlen = max_sense_len; 94*12767SJames.Kremer@Sun.COM } 95*12767SJames.Kremer@Sun.COM 96*12767SJames.Kremer@Sun.COM /* 97*12767SJames.Kremer@Sun.COM * Initialize data going to device 98*12767SJames.Kremer@Sun.COM */ 99*12767SJames.Kremer@Sun.COM static void 100*12767SJames.Kremer@Sun.COM set_scsi_pt_data_in(struct uscsi_cmd *uscsi, unsigned char *dxferp, 101*12767SJames.Kremer@Sun.COM int dxfer_len) 102*12767SJames.Kremer@Sun.COM { 103*12767SJames.Kremer@Sun.COM if (dxfer_len > 0) { 104*12767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp; 105*12767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len; 106*12767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | 107*12767SJames.Kremer@Sun.COM USCSI_RQENABLE; 108*12767SJames.Kremer@Sun.COM } 109*12767SJames.Kremer@Sun.COM } 110*12767SJames.Kremer@Sun.COM 111*12767SJames.Kremer@Sun.COM /* 112*12767SJames.Kremer@Sun.COM * Executes SCSI command(or at least forwards it to lower layers). 113*12767SJames.Kremer@Sun.COM */ 114*12767SJames.Kremer@Sun.COM static int 115*12767SJames.Kremer@Sun.COM do_scsi_pt(struct uscsi_cmd *uscsi, int fd, int time_secs) 116*12767SJames.Kremer@Sun.COM { 117*12767SJames.Kremer@Sun.COM if (time_secs > 0) 118*12767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = time_secs; 119*12767SJames.Kremer@Sun.COM 120*12767SJames.Kremer@Sun.COM if (ioctl(fd, USCSICMD, uscsi)) { 121*12767SJames.Kremer@Sun.COM /* Took an error */ 122*12767SJames.Kremer@Sun.COM return (errno); 123*12767SJames.Kremer@Sun.COM } 124*12767SJames.Kremer@Sun.COM return (0); 125*12767SJames.Kremer@Sun.COM } 126*12767SJames.Kremer@Sun.COM 127*12767SJames.Kremer@Sun.COM 128*12767SJames.Kremer@Sun.COM /* 129*12767SJames.Kremer@Sun.COM * Read log from device 130*12767SJames.Kremer@Sun.COM * Invokes a SCSI LOG SENSE command. 131*12767SJames.Kremer@Sun.COM * Return: 132*12767SJames.Kremer@Sun.COM * 0 -> success 133*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> Log Sense not supported, 134*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, 135*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready, 136*12767SJames.Kremer@Sun.COM * -1 -> other failure 137*12767SJames.Kremer@Sun.COM */ 138*12767SJames.Kremer@Sun.COM 139*12767SJames.Kremer@Sun.COM static int 140*12767SJames.Kremer@Sun.COM read_log(int sg_fd, unsigned char *resp, int mx_resp_len) 141*12767SJames.Kremer@Sun.COM { 142*12767SJames.Kremer@Sun.COM int res, ret; 143*12767SJames.Kremer@Sun.COM unsigned char logsCmdBlk[CDB_GROUP1] = 144*12767SJames.Kremer@Sun.COM {SCMD_LOG_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 145*12767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 146*12767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 147*12767SJames.Kremer@Sun.COM 148*12767SJames.Kremer@Sun.COM 149*12767SJames.Kremer@Sun.COM 150*12767SJames.Kremer@Sun.COM if (mx_resp_len > 0xffff) { 151*12767SJames.Kremer@Sun.COM return (-1); 152*12767SJames.Kremer@Sun.COM } 153*12767SJames.Kremer@Sun.COM logsCmdBlk[1] = 0; 154*12767SJames.Kremer@Sun.COM /* pc = 1, pg_code = 0x7 (logs page) */ 155*12767SJames.Kremer@Sun.COM /* (((pc << 6) & 0xc0) | (pg_code & 0x3f)) = 0x47; */ 156*12767SJames.Kremer@Sun.COM logsCmdBlk[2] = 0x47; 157*12767SJames.Kremer@Sun.COM /* pc = 1 current values */ 158*12767SJames.Kremer@Sun.COM logsCmdBlk[3] = 0; /* No subpage code */ 159*12767SJames.Kremer@Sun.COM logsCmdBlk[5] = 0; /* Want all logs starting from 0 */ 160*12767SJames.Kremer@Sun.COM logsCmdBlk[6] = 0; 161*12767SJames.Kremer@Sun.COM logsCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff); 162*12767SJames.Kremer@Sun.COM logsCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff); 163*12767SJames.Kremer@Sun.COM 164*12767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 165*12767SJames.Kremer@Sun.COM 166*12767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, logsCmdBlk, sizeof (logsCmdBlk)); 167*12767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 168*12767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, resp, mx_resp_len); 169*12767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 170*12767SJames.Kremer@Sun.COM if (res) { 171*12767SJames.Kremer@Sun.COM ret = res; 172*12767SJames.Kremer@Sun.COM } else { 173*12767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 174*12767SJames.Kremer@Sun.COM } 175*12767SJames.Kremer@Sun.COM return (ret); 176*12767SJames.Kremer@Sun.COM } 177*12767SJames.Kremer@Sun.COM 178*12767SJames.Kremer@Sun.COM /* 179*12767SJames.Kremer@Sun.COM * Save the logs by walking through the entries in the response buffer. 180*12767SJames.Kremer@Sun.COM * 181*12767SJames.Kremer@Sun.COM * resp buffer looks like: 182*12767SJames.Kremer@Sun.COM * 183*12767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+ 184*12767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 185*12767SJames.Kremer@Sun.COM * |Byte | | | | | | | | | 186*12767SJames.Kremer@Sun.COM * |=====+====================================================================| 187*12767SJames.Kremer@Sun.COM * | 0 | reserved | page code | 188*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 189*12767SJames.Kremer@Sun.COM * | 1 | Reserved | 190*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 191*12767SJames.Kremer@Sun.COM * | 2 |(MSB) Page Length(n-3) | 192*12767SJames.Kremer@Sun.COM * | -- | | 193*12767SJames.Kremer@Sun.COM * | 3 | (LSB) | 194*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 195*12767SJames.Kremer@Sun.COM * | 4 | Log Parameter (First)(Length X) | 196*12767SJames.Kremer@Sun.COM * | -- | | 197*12767SJames.Kremer@Sun.COM * | x+3 | | 198*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 199*12767SJames.Kremer@Sun.COM * |n-y+1| Log Parameter (Last)(Length y) | 200*12767SJames.Kremer@Sun.COM * | -- | | 201*12767SJames.Kremer@Sun.COM * | n | | 202*12767SJames.Kremer@Sun.COM * +==========================================================================+ 203*12767SJames.Kremer@Sun.COM * 204*12767SJames.Kremer@Sun.COM * Log parameter field looks like: 205*12767SJames.Kremer@Sun.COM * 206*12767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+ 207*12767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 208*12767SJames.Kremer@Sun.COM * |Byte | | | | | | | | | 209*12767SJames.Kremer@Sun.COM * |=====+====================================================================| 210*12767SJames.Kremer@Sun.COM * | 0 |(MSB) Parameter Code | 211*12767SJames.Kremer@Sun.COM * | -- | | 212*12767SJames.Kremer@Sun.COM * | 1 | (LSB) | 213*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 214*12767SJames.Kremer@Sun.COM * | 2 | DU | DS | TSD | ETC | TMC | LBIN | LP | 215*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 216*12767SJames.Kremer@Sun.COM * |3 | Paramter Length(n-3) | 217*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 218*12767SJames.Kremer@Sun.COM * | 4 | Parameter Values | 219*12767SJames.Kremer@Sun.COM * | -- | | 220*12767SJames.Kremer@Sun.COM * | n | | 221*12767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 222*12767SJames.Kremer@Sun.COM */ 223*12767SJames.Kremer@Sun.COM 224*12767SJames.Kremer@Sun.COM static int 225*12767SJames.Kremer@Sun.COM save_logs(unsigned char *resp, int len, nvlist_t *log_data, 226*12767SJames.Kremer@Sun.COM char *last_log_entry, unsigned long *seq_num_ret, int *number_log_entries) 227*12767SJames.Kremer@Sun.COM { 228*12767SJames.Kremer@Sun.COM int k, i; 229*12767SJames.Kremer@Sun.COM int paramCode; /* Parameter code */ 230*12767SJames.Kremer@Sun.COM int paramLen = 0; /* Paramter length */ 231*12767SJames.Kremer@Sun.COM int pcb; /* Paramter control Byte */ 232*12767SJames.Kremer@Sun.COM unsigned char *lpp; /* Log parameter pointer */ 233*12767SJames.Kremer@Sun.COM unsigned char *log_str_ptr; /* ptr to ascii str returend by expander */ 234*12767SJames.Kremer@Sun.COM 235*12767SJames.Kremer@Sun.COM unsigned long seq_num_ul = 0; 236*12767SJames.Kremer@Sun.COM char seq_num[10]; 237*12767SJames.Kremer@Sun.COM char log_event_type[10]; 238*12767SJames.Kremer@Sun.COM char log_code[10]; 239*12767SJames.Kremer@Sun.COM char log_level[10]; 240*12767SJames.Kremer@Sun.COM nvlist_t *entry; 241*12767SJames.Kremer@Sun.COM char entry_num[15]; 242*12767SJames.Kremer@Sun.COM int type; 243*12767SJames.Kremer@Sun.COM int match_found = 0; 244*12767SJames.Kremer@Sun.COM long current_seq_num; 245*12767SJames.Kremer@Sun.COM long last_num; 246*12767SJames.Kremer@Sun.COM char save_buffer[256]; 247*12767SJames.Kremer@Sun.COM char entry_added = 0; 248*12767SJames.Kremer@Sun.COM char *s; 249*12767SJames.Kremer@Sun.COM 250*12767SJames.Kremer@Sun.COM 251*12767SJames.Kremer@Sun.COM (void) memset(seq_num, 0, sizeof (seq_num)); 252*12767SJames.Kremer@Sun.COM 253*12767SJames.Kremer@Sun.COM *number_log_entries = 0; 254*12767SJames.Kremer@Sun.COM /* Initial log paramter pointer to point to first log entry */ 255*12767SJames.Kremer@Sun.COM /* The resp includes 4 bytes of header info and then log entries */ 256*12767SJames.Kremer@Sun.COM lpp = &resp[0] + 4; 257*12767SJames.Kremer@Sun.COM k = len; 258*12767SJames.Kremer@Sun.COM /* Find last sequence number from last log read */ 259*12767SJames.Kremer@Sun.COM if (last_log_entry != NULL && 260*12767SJames.Kremer@Sun.COM (strlen(last_log_entry) == SES_LOG_VALID_LOG_SIZE)) { 261*12767SJames.Kremer@Sun.COM (void) strncpy(seq_num, (const char *) last_log_entry + 262*12767SJames.Kremer@Sun.COM SES_LOG_SEQ_NUM_START, 8); 263*12767SJames.Kremer@Sun.COM last_num = strtoul(seq_num, 0, 16); 264*12767SJames.Kremer@Sun.COM /* save this in case there are no new entries */ 265*12767SJames.Kremer@Sun.COM seq_num_ul = last_num; 266*12767SJames.Kremer@Sun.COM 267*12767SJames.Kremer@Sun.COM /* First find if there are duplicate entries */ 268*12767SJames.Kremer@Sun.COM lpp = &resp[0] + 4; 269*12767SJames.Kremer@Sun.COM 270*12767SJames.Kremer@Sun.COM /* 271*12767SJames.Kremer@Sun.COM * Start walking each log entry in return buffer looking for 272*12767SJames.Kremer@Sun.COM * a duplicate entry. 273*12767SJames.Kremer@Sun.COM */ 274*12767SJames.Kremer@Sun.COM for (; k > 0; k -= paramLen) { 275*12767SJames.Kremer@Sun.COM if (k < 3) { 276*12767SJames.Kremer@Sun.COM /* 277*12767SJames.Kremer@Sun.COM * Should always have at least 3 Bytes for 278*12767SJames.Kremer@Sun.COM * each entry 279*12767SJames.Kremer@Sun.COM * If not, it must be a bad record so stop 280*12767SJames.Kremer@Sun.COM * processing 281*12767SJames.Kremer@Sun.COM */ 282*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 283*12767SJames.Kremer@Sun.COM log_data = NULL; 284*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_SHORT_LOG_PARAM_INIT); 285*12767SJames.Kremer@Sun.COM } 286*12767SJames.Kremer@Sun.COM pcb = lpp[2]; 287*12767SJames.Kremer@Sun.COM paramLen = lpp[3] + 4; 288*12767SJames.Kremer@Sun.COM /* 289*12767SJames.Kremer@Sun.COM * initial log_str_ptr to point to string info returned 290*12767SJames.Kremer@Sun.COM * by expander 291*12767SJames.Kremer@Sun.COM * first 4 bytes of log 292*12767SJames.Kremer@Sun.COM * parameter are 2 param: 293*12767SJames.Kremer@Sun.COM * codes Control byte, Parameter length 294*12767SJames.Kremer@Sun.COM */ 295*12767SJames.Kremer@Sun.COM log_str_ptr = lpp + 4; 296*12767SJames.Kremer@Sun.COM 297*12767SJames.Kremer@Sun.COM if (paramLen > 4) { 298*12767SJames.Kremer@Sun.COM if ((pcb & 0x1) && !(pcb & 2)) { 299*12767SJames.Kremer@Sun.COM 300*12767SJames.Kremer@Sun.COM (void) strncpy(seq_num, 301*12767SJames.Kremer@Sun.COM (const char *)log_str_ptr + 302*12767SJames.Kremer@Sun.COM SES_LOG_SEQ_NUM_START, 8); 303*12767SJames.Kremer@Sun.COM current_seq_num = strtoul(seq_num, 0, 304*12767SJames.Kremer@Sun.COM 16); 305*12767SJames.Kremer@Sun.COM 306*12767SJames.Kremer@Sun.COM if (current_seq_num == last_num) { 307*12767SJames.Kremer@Sun.COM /* 308*12767SJames.Kremer@Sun.COM * Check to see if this is the 309*12767SJames.Kremer@Sun.COM * same line 310*12767SJames.Kremer@Sun.COM */ 311*12767SJames.Kremer@Sun.COM if (strncmp( 312*12767SJames.Kremer@Sun.COM (char *)log_str_ptr, 313*12767SJames.Kremer@Sun.COM last_log_entry, 314*12767SJames.Kremer@Sun.COM SES_LOG_VALID_LOG_SIZE) == 315*12767SJames.Kremer@Sun.COM 0) { 316*12767SJames.Kremer@Sun.COM /* 317*12767SJames.Kremer@Sun.COM * Found an exact 318*12767SJames.Kremer@Sun.COM * match 319*12767SJames.Kremer@Sun.COM */ 320*12767SJames.Kremer@Sun.COM lpp += paramLen; 321*12767SJames.Kremer@Sun.COM k -= paramLen; 322*12767SJames.Kremer@Sun.COM match_found = 1; 323*12767SJames.Kremer@Sun.COM break; 324*12767SJames.Kremer@Sun.COM } 325*12767SJames.Kremer@Sun.COM } 326*12767SJames.Kremer@Sun.COM } 327*12767SJames.Kremer@Sun.COM } 328*12767SJames.Kremer@Sun.COM lpp += paramLen; 329*12767SJames.Kremer@Sun.COM } 330*12767SJames.Kremer@Sun.COM } 331*12767SJames.Kremer@Sun.COM if (!match_found) { 332*12767SJames.Kremer@Sun.COM lpp = &resp[0] + 4; 333*12767SJames.Kremer@Sun.COM k = len; 334*12767SJames.Kremer@Sun.COM } 335*12767SJames.Kremer@Sun.COM 336*12767SJames.Kremer@Sun.COM (void) memset(log_event_type, 0, sizeof (log_event_type)); 337*12767SJames.Kremer@Sun.COM (void) memset(seq_num, 0, sizeof (seq_num)); 338*12767SJames.Kremer@Sun.COM (void) memset(log_code, 0, sizeof (log_code)); 339*12767SJames.Kremer@Sun.COM (void) memset(save_buffer, 0, sizeof (save_buffer)); 340*12767SJames.Kremer@Sun.COM (void) memset(log_level, 0, sizeof (log_level)); 341*12767SJames.Kremer@Sun.COM 342*12767SJames.Kremer@Sun.COM /* K will be initialized from above */ 343*12767SJames.Kremer@Sun.COM for (; k > 0; k -= paramLen) { 344*12767SJames.Kremer@Sun.COM if (k < 3) { 345*12767SJames.Kremer@Sun.COM /* Should always have at least 3 Bytes for each entry */ 346*12767SJames.Kremer@Sun.COM /* If not, it must be a bad record so stop processing */ 347*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 348*12767SJames.Kremer@Sun.COM log_data = NULL; 349*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_SHORT_LOG_PARAM); 350*12767SJames.Kremer@Sun.COM } 351*12767SJames.Kremer@Sun.COM paramCode = (lpp[0] << 8) + lpp[1]; 352*12767SJames.Kremer@Sun.COM pcb = lpp[2]; 353*12767SJames.Kremer@Sun.COM paramLen = lpp[3] + 4; 354*12767SJames.Kremer@Sun.COM /* 355*12767SJames.Kremer@Sun.COM * initial log_str_ptr to point to string info of the log entry 356*12767SJames.Kremer@Sun.COM * First 4 bytes of log entry contains param code, control 357*12767SJames.Kremer@Sun.COM * byte, length 358*12767SJames.Kremer@Sun.COM */ 359*12767SJames.Kremer@Sun.COM log_str_ptr = lpp + 4; 360*12767SJames.Kremer@Sun.COM 361*12767SJames.Kremer@Sun.COM /* 362*12767SJames.Kremer@Sun.COM * Format of log str is as follows 363*12767SJames.Kremer@Sun.COM * "%8x %8x %8x %8x %8x %8x %8x %8x", 364*12767SJames.Kremer@Sun.COM * log_entry.log_word0, log_entry.ts_u, log_entry.ts_l, 365*12767SJames.Kremer@Sun.COM * log_entry.seq_num, log_entry.log_code, log_entry.log_word2, 366*12767SJames.Kremer@Sun.COM * log_entry.log_word3, log_entry.log_word4 367*12767SJames.Kremer@Sun.COM * following example has extra spaces removed to fit in 80 char 368*12767SJames.Kremer@Sun.COM * 40004 0 42d5f5fe 185b 630002 fd0800 50800207 e482813 369*12767SJames.Kremer@Sun.COM */ 370*12767SJames.Kremer@Sun.COM if (paramLen > 4) { 371*12767SJames.Kremer@Sun.COM if ((pcb & 0x1) && !(pcb & 2)) { 372*12767SJames.Kremer@Sun.COM 373*12767SJames.Kremer@Sun.COM (void) strncpy(save_buffer, 374*12767SJames.Kremer@Sun.COM (const char *)log_str_ptr, 375*12767SJames.Kremer@Sun.COM SES_LOG_VALID_LOG_SIZE); 376*12767SJames.Kremer@Sun.COM for (i = 0; (i < 8) && (s = strtok(i ? 0 : 377*12767SJames.Kremer@Sun.COM (char *)log_str_ptr, " ")); i++) { 378*12767SJames.Kremer@Sun.COM char *ulp; 379*12767SJames.Kremer@Sun.COM switch (i) { 380*12767SJames.Kremer@Sun.COM case 0: 381*12767SJames.Kremer@Sun.COM /* event type */ 382*12767SJames.Kremer@Sun.COM ulp = (char *) 383*12767SJames.Kremer@Sun.COM &log_event_type; 384*12767SJames.Kremer@Sun.COM break; 385*12767SJames.Kremer@Sun.COM case 3: 386*12767SJames.Kremer@Sun.COM /* sequence number */ 387*12767SJames.Kremer@Sun.COM ulp = (char *) 388*12767SJames.Kremer@Sun.COM &seq_num; 389*12767SJames.Kremer@Sun.COM break; 390*12767SJames.Kremer@Sun.COM case 4: 391*12767SJames.Kremer@Sun.COM /* log code */ 392*12767SJames.Kremer@Sun.COM ulp = (char *) 393*12767SJames.Kremer@Sun.COM &log_code; 394*12767SJames.Kremer@Sun.COM break; 395*12767SJames.Kremer@Sun.COM default: 396*12767SJames.Kremer@Sun.COM ulp = 0; 397*12767SJames.Kremer@Sun.COM } 398*12767SJames.Kremer@Sun.COM 399*12767SJames.Kremer@Sun.COM if (ulp) { 400*12767SJames.Kremer@Sun.COM (void) strncpy(ulp, s, 8); 401*12767SJames.Kremer@Sun.COM } 402*12767SJames.Kremer@Sun.COM } 403*12767SJames.Kremer@Sun.COM 404*12767SJames.Kremer@Sun.COM 405*12767SJames.Kremer@Sun.COM seq_num_ul = strtoul(seq_num, 0, 16); 406*12767SJames.Kremer@Sun.COM 407*12767SJames.Kremer@Sun.COM (void) strncpy(log_level, 408*12767SJames.Kremer@Sun.COM (const char *) log_str_ptr + 409*12767SJames.Kremer@Sun.COM SES_LOG_LEVEL_START, 1); 410*12767SJames.Kremer@Sun.COM 411*12767SJames.Kremer@Sun.COM /* event type is in log_event_type */ 412*12767SJames.Kremer@Sun.COM /* 4x004 = looking for x */ 413*12767SJames.Kremer@Sun.COM type = (strtoul(log_event_type, 0, 16) >> 12) & 414*12767SJames.Kremer@Sun.COM 0xf; 415*12767SJames.Kremer@Sun.COM 416*12767SJames.Kremer@Sun.COM /* 417*12767SJames.Kremer@Sun.COM * Check type. If type is 1, level needs to be 418*12767SJames.Kremer@Sun.COM * changed to FATAL. If type is something other 419*12767SJames.Kremer@Sun.COM * than 0 or 1, they are info only. 420*12767SJames.Kremer@Sun.COM */ 421*12767SJames.Kremer@Sun.COM if (type == 1) { 422*12767SJames.Kremer@Sun.COM (void) strcpy(log_level, "4"); 423*12767SJames.Kremer@Sun.COM } else if (type > 1) { 424*12767SJames.Kremer@Sun.COM /* These are not application log */ 425*12767SJames.Kremer@Sun.COM /* entries */ 426*12767SJames.Kremer@Sun.COM /* make them info only */ 427*12767SJames.Kremer@Sun.COM (void) strcpy(log_level, "0"); 428*12767SJames.Kremer@Sun.COM } 429*12767SJames.Kremer@Sun.COM 430*12767SJames.Kremer@Sun.COM /* Add this entry to the nvlist log data */ 431*12767SJames.Kremer@Sun.COM if (nvlist_alloc(&entry, 432*12767SJames.Kremer@Sun.COM NV_UNIQUE_NAME, 0) != 0) { 433*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 434*12767SJames.Kremer@Sun.COM log_data = NULL; 435*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NV_UNIQUE); 436*12767SJames.Kremer@Sun.COM } 437*12767SJames.Kremer@Sun.COM 438*12767SJames.Kremer@Sun.COM 439*12767SJames.Kremer@Sun.COM if (nvlist_add_string(entry, ENTRY_LOG, 440*12767SJames.Kremer@Sun.COM save_buffer) != 0) { 441*12767SJames.Kremer@Sun.COM nvlist_free(entry); 442*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 443*12767SJames.Kremer@Sun.COM log_data = NULL; 444*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NV_LOG); 445*12767SJames.Kremer@Sun.COM } 446*12767SJames.Kremer@Sun.COM 447*12767SJames.Kremer@Sun.COM if (nvlist_add_string(entry, ENTRY_CODE, 448*12767SJames.Kremer@Sun.COM log_code) != 0) { 449*12767SJames.Kremer@Sun.COM nvlist_free(entry); 450*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 451*12767SJames.Kremer@Sun.COM log_data = NULL; 452*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NV_CODE); 453*12767SJames.Kremer@Sun.COM } 454*12767SJames.Kremer@Sun.COM if (nvlist_add_string(entry, ENTRY_SEVERITY, 455*12767SJames.Kremer@Sun.COM log_level) != 0) { 456*12767SJames.Kremer@Sun.COM nvlist_free(entry); 457*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 458*12767SJames.Kremer@Sun.COM log_data = NULL; 459*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NV_SEV); 460*12767SJames.Kremer@Sun.COM } 461*12767SJames.Kremer@Sun.COM 462*12767SJames.Kremer@Sun.COM (void) snprintf(entry_num, sizeof (entry_num), 463*12767SJames.Kremer@Sun.COM "%s%d", ENTRY_PREFIX, paramCode); 464*12767SJames.Kremer@Sun.COM 465*12767SJames.Kremer@Sun.COM if (nvlist_add_nvlist(log_data, entry_num, 466*12767SJames.Kremer@Sun.COM entry) != 0) { 467*12767SJames.Kremer@Sun.COM nvlist_free(entry); 468*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 469*12767SJames.Kremer@Sun.COM log_data = NULL; 470*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NV_ENTRY); 471*12767SJames.Kremer@Sun.COM } 472*12767SJames.Kremer@Sun.COM nvlist_free(entry); 473*12767SJames.Kremer@Sun.COM 474*12767SJames.Kremer@Sun.COM entry_added = 1; 475*12767SJames.Kremer@Sun.COM (*number_log_entries)++; 476*12767SJames.Kremer@Sun.COM 477*12767SJames.Kremer@Sun.COM } 478*12767SJames.Kremer@Sun.COM } 479*12767SJames.Kremer@Sun.COM lpp += paramLen; 480*12767SJames.Kremer@Sun.COM 481*12767SJames.Kremer@Sun.COM } 482*12767SJames.Kremer@Sun.COM if (entry_added) { 483*12767SJames.Kremer@Sun.COM /* Update the last log entry string with last one read */ 484*12767SJames.Kremer@Sun.COM (void) strncpy(last_log_entry, save_buffer, MAXNAMELEN); 485*12767SJames.Kremer@Sun.COM } 486*12767SJames.Kremer@Sun.COM *seq_num_ret = seq_num_ul; 487*12767SJames.Kremer@Sun.COM 488*12767SJames.Kremer@Sun.COM return (0); 489*12767SJames.Kremer@Sun.COM } 490*12767SJames.Kremer@Sun.COM 491*12767SJames.Kremer@Sun.COM 492*12767SJames.Kremer@Sun.COM 493*12767SJames.Kremer@Sun.COM /* Setup struct to send command to device */ 494*12767SJames.Kremer@Sun.COM static void 495*12767SJames.Kremer@Sun.COM set_scsi_pt_data_out(struct uscsi_cmd *uscsi, const unsigned char *dxferp, 496*12767SJames.Kremer@Sun.COM int dxfer_len) 497*12767SJames.Kremer@Sun.COM { 498*12767SJames.Kremer@Sun.COM if (dxfer_len > 0) { 499*12767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp; 500*12767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len; 501*12767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_WRITE | USCSI_ISOLATE | 502*12767SJames.Kremer@Sun.COM USCSI_RQENABLE; 503*12767SJames.Kremer@Sun.COM } 504*12767SJames.Kremer@Sun.COM } 505*12767SJames.Kremer@Sun.COM 506*12767SJames.Kremer@Sun.COM /* 507*12767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SENSE(10) command. 508*12767SJames.Kremer@Sun.COM * Return: 509*12767SJames.Kremer@Sun.COM * 0 for success 510*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> invalid opcode 511*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb 512*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready 513*12767SJames.Kremer@Sun.COM * -1 -> other failure 514*12767SJames.Kremer@Sun.COM */ 515*12767SJames.Kremer@Sun.COM 516*12767SJames.Kremer@Sun.COM static int 517*12767SJames.Kremer@Sun.COM sg_ll_mode_sense10(int sg_fd, void * resp, int mx_resp_len) 518*12767SJames.Kremer@Sun.COM { 519*12767SJames.Kremer@Sun.COM int res, ret; 520*12767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = 521*12767SJames.Kremer@Sun.COM {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 522*12767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 523*12767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 524*12767SJames.Kremer@Sun.COM 525*12767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0; 526*12767SJames.Kremer@Sun.COM modesCmdBlk[2] = 0; /* page code 0 vendor specific */ 527*12767SJames.Kremer@Sun.COM modesCmdBlk[3] = 0; 528*12767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff); 529*12767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff); 530*12767SJames.Kremer@Sun.COM 531*12767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 532*12767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk)); 533*12767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 534*12767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, (unsigned char *) resp, mx_resp_len); 535*12767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 536*12767SJames.Kremer@Sun.COM if (res) { 537*12767SJames.Kremer@Sun.COM ret = res; 538*12767SJames.Kremer@Sun.COM } else { 539*12767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 540*12767SJames.Kremer@Sun.COM } 541*12767SJames.Kremer@Sun.COM return (ret); 542*12767SJames.Kremer@Sun.COM } 543*12767SJames.Kremer@Sun.COM 544*12767SJames.Kremer@Sun.COM /* 545*12767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SELECT(10) command. 546*12767SJames.Kremer@Sun.COM * Return: 547*12767SJames.Kremer@Sun.COM * 0 for success. 548*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP for invalid opcode 549*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, 550*12767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready, 551*12767SJames.Kremer@Sun.COM * -1 -> other failure 552*12767SJames.Kremer@Sun.COM */ 553*12767SJames.Kremer@Sun.COM static int 554*12767SJames.Kremer@Sun.COM sg_ll_mode_select10(int sg_fd, void * paramp, int param_len) 555*12767SJames.Kremer@Sun.COM { 556*12767SJames.Kremer@Sun.COM int res, ret; 557*12767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] = 558*12767SJames.Kremer@Sun.COM {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 559*12767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 560*12767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 561*12767SJames.Kremer@Sun.COM 562*12767SJames.Kremer@Sun.COM 563*12767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0; 564*12767SJames.Kremer@Sun.COM /* 565*12767SJames.Kremer@Sun.COM * modesCmdBlk 2 equal 0 PC 0 return current page code 0 return 566*12767SJames.Kremer@Sun.COM * vendor specific 567*12767SJames.Kremer@Sun.COM */ 568*12767SJames.Kremer@Sun.COM 569*12767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); 570*12767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char)(param_len & 0xff); 571*12767SJames.Kremer@Sun.COM 572*12767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 573*12767SJames.Kremer@Sun.COM 574*12767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk)); 575*12767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 576*12767SJames.Kremer@Sun.COM set_scsi_pt_data_out(&uscsi, (unsigned char *) paramp, param_len); 577*12767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 578*12767SJames.Kremer@Sun.COM if (res) { 579*12767SJames.Kremer@Sun.COM ret = res; 580*12767SJames.Kremer@Sun.COM } else { 581*12767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 582*12767SJames.Kremer@Sun.COM } 583*12767SJames.Kremer@Sun.COM return (ret); 584*12767SJames.Kremer@Sun.COM } 585*12767SJames.Kremer@Sun.COM 586*12767SJames.Kremer@Sun.COM 587*12767SJames.Kremer@Sun.COM 588*12767SJames.Kremer@Sun.COM /* 589*12767SJames.Kremer@Sun.COM * MODE SENSE 10 commands yield a response that has block descriptors followed 590*12767SJames.Kremer@Sun.COM * by mode pages. In most cases users are interested in the first mode page. 591*12767SJames.Kremer@Sun.COM * This function returns the(byte) offset of the start of the first mode page. 592*12767SJames.Kremer@Sun.COM * Returns >= 0 is successful or -1 if failure. If there is a failure 593*12767SJames.Kremer@Sun.COM * a message is written to err_buff. 594*12767SJames.Kremer@Sun.COM */ 595*12767SJames.Kremer@Sun.COM 596*12767SJames.Kremer@Sun.COM /* 597*12767SJames.Kremer@Sun.COM * return data looks like: 598*12767SJames.Kremer@Sun.COM * Table 92 - Mode parameter header(10) 599*12767SJames.Kremer@Sun.COM * Bit 600*12767SJames.Kremer@Sun.COM * Byte 601*12767SJames.Kremer@Sun.COM * 7 6 5 4 3 2 1 0 602*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 603*12767SJames.Kremer@Sun.COM * 0 MSB Data length 604*12767SJames.Kremer@Sun.COM * 1 LSB Data length 605*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 606*12767SJames.Kremer@Sun.COM * 2 Medium type 607*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 608*12767SJames.Kremer@Sun.COM * 3 Device-specific parameter 609*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 610*12767SJames.Kremer@Sun.COM * 4 Reserved 611*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 612*12767SJames.Kremer@Sun.COM * 5 Reserved 613*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 614*12767SJames.Kremer@Sun.COM * 6 MSB block descriptor length 615*12767SJames.Kremer@Sun.COM * 7 LSB block descriptor length 616*12767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 617*12767SJames.Kremer@Sun.COM * block desciptors.... 618*12767SJames.Kremer@Sun.COM * ----------------------- 619*12767SJames.Kremer@Sun.COM * mode sense page: 620*12767SJames.Kremer@Sun.COM * 0 : ps Reserved : page Code 621*12767SJames.Kremer@Sun.COM * 1 : Page Length(n-1) 622*12767SJames.Kremer@Sun.COM * 2-N Mode parameters 623*12767SJames.Kremer@Sun.COM */ 624*12767SJames.Kremer@Sun.COM static int 625*12767SJames.Kremer@Sun.COM sg_mode_page_offset(const unsigned char *resp, int resp_len, 626*12767SJames.Kremer@Sun.COM char *err_buff, int err_buff_len) 627*12767SJames.Kremer@Sun.COM { 628*12767SJames.Kremer@Sun.COM int bd_len; 629*12767SJames.Kremer@Sun.COM int calc_len; 630*12767SJames.Kremer@Sun.COM int offset; 631*12767SJames.Kremer@Sun.COM 632*12767SJames.Kremer@Sun.COM if ((NULL == resp) || (resp_len < 8)) { 633*12767SJames.Kremer@Sun.COM /* Too short of a response buffer */ 634*12767SJames.Kremer@Sun.COM return (-1); 635*12767SJames.Kremer@Sun.COM } 636*12767SJames.Kremer@Sun.COM 637*12767SJames.Kremer@Sun.COM calc_len = (resp[0] << 8) + resp[1] + 2; 638*12767SJames.Kremer@Sun.COM bd_len = (resp[6] << 8) + resp[7]; 639*12767SJames.Kremer@Sun.COM 640*12767SJames.Kremer@Sun.COM /* LongLBA doesn't change this calculation */ 641*12767SJames.Kremer@Sun.COM offset = bd_len + MODE10_RESP_HDR_LEN; 642*12767SJames.Kremer@Sun.COM 643*12767SJames.Kremer@Sun.COM if ((offset + 2) > resp_len) { 644*12767SJames.Kremer@Sun.COM (void) snprintf(err_buff, err_buff_len, 645*12767SJames.Kremer@Sun.COM "given response length " 646*12767SJames.Kremer@Sun.COM "too small, offset=%d given_len=%d bd_len=%d\n", 647*12767SJames.Kremer@Sun.COM offset, resp_len, bd_len); 648*12767SJames.Kremer@Sun.COM offset = -1; 649*12767SJames.Kremer@Sun.COM } else if ((offset + 2) > calc_len) { 650*12767SJames.Kremer@Sun.COM (void) snprintf(err_buff, err_buff_len, "calculated response " 651*12767SJames.Kremer@Sun.COM "length too small, offset=%d calc_len=%d bd_len=%d\n", 652*12767SJames.Kremer@Sun.COM offset, calc_len, bd_len); 653*12767SJames.Kremer@Sun.COM offset = -1; 654*12767SJames.Kremer@Sun.COM } 655*12767SJames.Kremer@Sun.COM return (offset); 656*12767SJames.Kremer@Sun.COM } 657*12767SJames.Kremer@Sun.COM 658*12767SJames.Kremer@Sun.COM /* 659*12767SJames.Kremer@Sun.COM * Clear logs 660*12767SJames.Kremer@Sun.COM */ 661*12767SJames.Kremer@Sun.COM static int 662*12767SJames.Kremer@Sun.COM clear_log(int sg_fd, unsigned long seq_num, long poll_time) 663*12767SJames.Kremer@Sun.COM { 664*12767SJames.Kremer@Sun.COM 665*12767SJames.Kremer@Sun.COM int res, alloc_len, off; 666*12767SJames.Kremer@Sun.COM int md_len; 667*12767SJames.Kremer@Sun.COM int read_in_len = 0; 668*12767SJames.Kremer@Sun.COM unsigned char ref_md[MX_ALLOC_LEN]; 669*12767SJames.Kremer@Sun.COM char ebuff[EBUFF_SZ]; 670*12767SJames.Kremer@Sun.COM struct log_clear_control_struct clear_data; 671*12767SJames.Kremer@Sun.COM long myhostid; 672*12767SJames.Kremer@Sun.COM int error = 0; 673*12767SJames.Kremer@Sun.COM 674*12767SJames.Kremer@Sun.COM (void) memset(&clear_data, 0, sizeof (clear_data)); 675*12767SJames.Kremer@Sun.COM 676*12767SJames.Kremer@Sun.COM clear_data.pageControls = 0x40; 677*12767SJames.Kremer@Sun.COM clear_data.subpage_code = 0; 678*12767SJames.Kremer@Sun.COM clear_data.page_lengthLower = 0x16; 679*12767SJames.Kremer@Sun.COM 680*12767SJames.Kremer@Sun.COM myhostid = gethostid(); 681*12767SJames.Kremer@Sun.COM /* 0 -> 11 are memset to 0 */ 682*12767SJames.Kremer@Sun.COM clear_data.host_id[12] = (myhostid & 0xff000000) >> 24; 683*12767SJames.Kremer@Sun.COM clear_data.host_id[13] = (myhostid & 0xff0000) >> 16; 684*12767SJames.Kremer@Sun.COM clear_data.host_id[14] = (myhostid & 0xff00) >> 8; 685*12767SJames.Kremer@Sun.COM clear_data.host_id[15] = myhostid & 0xff; 686*12767SJames.Kremer@Sun.COM 687*12767SJames.Kremer@Sun.COM /* Timeout set to 32 seconds for now */ 688*12767SJames.Kremer@Sun.COM /* Add 5 minutes to poll time to allow for data retrievel time */ 689*12767SJames.Kremer@Sun.COM poll_time = poll_time + 300; 690*12767SJames.Kremer@Sun.COM clear_data.timeout[0] = (poll_time & 0xff00) >> 8; 691*12767SJames.Kremer@Sun.COM clear_data.timeout[1] = poll_time & 0xff; 692*12767SJames.Kremer@Sun.COM 693*12767SJames.Kremer@Sun.COM clear_data.seq_clear[0] = (seq_num & 0xff000000) >> 24; 694*12767SJames.Kremer@Sun.COM clear_data.seq_clear[1] = (seq_num & 0xff0000) >> 16; 695*12767SJames.Kremer@Sun.COM clear_data.seq_clear[2] = (seq_num & 0xff00) >> 8; 696*12767SJames.Kremer@Sun.COM clear_data.seq_clear[3] = (seq_num & 0xff); 697*12767SJames.Kremer@Sun.COM 698*12767SJames.Kremer@Sun.COM read_in_len = sizeof (clear_data); 699*12767SJames.Kremer@Sun.COM 700*12767SJames.Kremer@Sun.COM 701*12767SJames.Kremer@Sun.COM /* do MODE SENSE to fetch current values */ 702*12767SJames.Kremer@Sun.COM (void) memset(ref_md, 0, MX_ALLOC_LEN); 703*12767SJames.Kremer@Sun.COM alloc_len = MX_ALLOC_LEN; 704*12767SJames.Kremer@Sun.COM 705*12767SJames.Kremer@Sun.COM 706*12767SJames.Kremer@Sun.COM res = sg_ll_mode_sense10(sg_fd, ref_md, alloc_len); 707*12767SJames.Kremer@Sun.COM if (0 != res) { 708*12767SJames.Kremer@Sun.COM /* Error during mode sense */ 709*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE; 710*12767SJames.Kremer@Sun.COM return (error); 711*12767SJames.Kremer@Sun.COM } 712*12767SJames.Kremer@Sun.COM 713*12767SJames.Kremer@Sun.COM /* Setup mode Select to clear logs */ 714*12767SJames.Kremer@Sun.COM off = sg_mode_page_offset(ref_md, alloc_len, ebuff, EBUFF_SZ); 715*12767SJames.Kremer@Sun.COM if (off < 0) { 716*12767SJames.Kremer@Sun.COM /* Mode page offset error */ 717*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE_OFFSET; 718*12767SJames.Kremer@Sun.COM return (error); 719*12767SJames.Kremer@Sun.COM } 720*12767SJames.Kremer@Sun.COM md_len = (ref_md[0] << 8) + ref_md[1] + 2; 721*12767SJames.Kremer@Sun.COM 722*12767SJames.Kremer@Sun.COM ref_md[0] = 0; 723*12767SJames.Kremer@Sun.COM ref_md[1] = 0; 724*12767SJames.Kremer@Sun.COM 725*12767SJames.Kremer@Sun.COM if (md_len > alloc_len) { 726*12767SJames.Kremer@Sun.COM /* Data length to large */ 727*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_DATA_LEN; 728*12767SJames.Kremer@Sun.COM return (error); 729*12767SJames.Kremer@Sun.COM } 730*12767SJames.Kremer@Sun.COM 731*12767SJames.Kremer@Sun.COM if ((md_len - off) != read_in_len) { 732*12767SJames.Kremer@Sun.COM /* Content length not correct */ 733*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_CONTENT_LEN; 734*12767SJames.Kremer@Sun.COM return (error); 735*12767SJames.Kremer@Sun.COM } 736*12767SJames.Kremer@Sun.COM 737*12767SJames.Kremer@Sun.COM if ((clear_data.pageControls & 0x40) != (ref_md[off] & 0x40)) { 738*12767SJames.Kremer@Sun.COM /* reference model doesn't have use subpage format bit set */ 739*12767SJames.Kremer@Sun.COM /* Even though it should have */ 740*12767SJames.Kremer@Sun.COM /* don't send the command */ 741*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_FORMAT_PAGE_ERROR; 742*12767SJames.Kremer@Sun.COM return (error); 743*12767SJames.Kremer@Sun.COM } 744*12767SJames.Kremer@Sun.COM 745*12767SJames.Kremer@Sun.COM (void) memcpy(ref_md + off, (const void *) & clear_data, 746*12767SJames.Kremer@Sun.COM sizeof (clear_data)); 747*12767SJames.Kremer@Sun.COM 748*12767SJames.Kremer@Sun.COM res = sg_ll_mode_select10(sg_fd, ref_md, md_len); 749*12767SJames.Kremer@Sun.COM if (res != 0) { 750*12767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SELECT; 751*12767SJames.Kremer@Sun.COM return (error); 752*12767SJames.Kremer@Sun.COM } 753*12767SJames.Kremer@Sun.COM 754*12767SJames.Kremer@Sun.COM return (error); 755*12767SJames.Kremer@Sun.COM 756*12767SJames.Kremer@Sun.COM 757*12767SJames.Kremer@Sun.COM } 758*12767SJames.Kremer@Sun.COM /* 759*12767SJames.Kremer@Sun.COM * Gather data from given device. 760*12767SJames.Kremer@Sun.COM */ 761*12767SJames.Kremer@Sun.COM static int 762*12767SJames.Kremer@Sun.COM gatherData(char *device_name, nvlist_t *log_data, char *last_log_entry, 763*12767SJames.Kremer@Sun.COM long poll_time, int *number_log_entries) 764*12767SJames.Kremer@Sun.COM { 765*12767SJames.Kremer@Sun.COM int sg_fd; 766*12767SJames.Kremer@Sun.COM unsigned long seq_num; 767*12767SJames.Kremer@Sun.COM int pg_len, resp_len, res; 768*12767SJames.Kremer@Sun.COM unsigned char rsp_buff[MX_ALLOC_LEN]; 769*12767SJames.Kremer@Sun.COM int error; 770*12767SJames.Kremer@Sun.COM 771*12767SJames.Kremer@Sun.COM 772*12767SJames.Kremer@Sun.COM 773*12767SJames.Kremer@Sun.COM /* Open device */ 774*12767SJames.Kremer@Sun.COM if ((sg_fd = open_device(device_name)) < 0) { 775*12767SJames.Kremer@Sun.COM /* Failed to open device */ 776*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 777*12767SJames.Kremer@Sun.COM log_data = NULL; 778*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_OPEN_DEVICE); 779*12767SJames.Kremer@Sun.COM } 780*12767SJames.Kremer@Sun.COM 781*12767SJames.Kremer@Sun.COM /* Read the logs */ 782*12767SJames.Kremer@Sun.COM (void) memset(rsp_buff, 0, sizeof (rsp_buff)); 783*12767SJames.Kremer@Sun.COM resp_len = 0x8000; /* Maximum size available to read */ 784*12767SJames.Kremer@Sun.COM res = read_log(sg_fd, rsp_buff, resp_len); 785*12767SJames.Kremer@Sun.COM 786*12767SJames.Kremer@Sun.COM if (res == 0) { 787*12767SJames.Kremer@Sun.COM pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; 788*12767SJames.Kremer@Sun.COM if ((pg_len + 4) > resp_len) { 789*12767SJames.Kremer@Sun.COM /* Didn't get entire response */ 790*12767SJames.Kremer@Sun.COM /* Process what we did get */ 791*12767SJames.Kremer@Sun.COM pg_len = resp_len - 4; 792*12767SJames.Kremer@Sun.COM } 793*12767SJames.Kremer@Sun.COM } else { 794*12767SJames.Kremer@Sun.COM /* Some sort of Error during read of logs */ 795*12767SJames.Kremer@Sun.COM nvlist_free(log_data); 796*12767SJames.Kremer@Sun.COM log_data = NULL; 797*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_READ_DEVICE); 798*12767SJames.Kremer@Sun.COM } 799*12767SJames.Kremer@Sun.COM 800*12767SJames.Kremer@Sun.COM /* Save the logs */ 801*12767SJames.Kremer@Sun.COM error = save_logs(rsp_buff, pg_len, log_data, last_log_entry, 802*12767SJames.Kremer@Sun.COM &seq_num, number_log_entries); 803*12767SJames.Kremer@Sun.COM if (error != 0) { 804*12767SJames.Kremer@Sun.COM return (error); 805*12767SJames.Kremer@Sun.COM } 806*12767SJames.Kremer@Sun.COM /* Clear logs */ 807*12767SJames.Kremer@Sun.COM error = clear_log(sg_fd, seq_num, poll_time); 808*12767SJames.Kremer@Sun.COM 809*12767SJames.Kremer@Sun.COM (void) close(sg_fd); 810*12767SJames.Kremer@Sun.COM 811*12767SJames.Kremer@Sun.COM return (error); 812*12767SJames.Kremer@Sun.COM 813*12767SJames.Kremer@Sun.COM } 814*12767SJames.Kremer@Sun.COM 815*12767SJames.Kremer@Sun.COM /* 816*12767SJames.Kremer@Sun.COM * Access the SES target identified by the indicated path. Read the logs 817*12767SJames.Kremer@Sun.COM * and return them in a nvlist. 818*12767SJames.Kremer@Sun.COM */ 819*12767SJames.Kremer@Sun.COM int 820*12767SJames.Kremer@Sun.COM access_ses_log(struct ses_log_call_struct *data) 821*12767SJames.Kremer@Sun.COM { 822*12767SJames.Kremer@Sun.COM char real_path[MAXPATHLEN]; 823*12767SJames.Kremer@Sun.COM long poll_time; 824*12767SJames.Kremer@Sun.COM struct stat buffer; 825*12767SJames.Kremer@Sun.COM int error; 826*12767SJames.Kremer@Sun.COM 827*12767SJames.Kremer@Sun.COM if (data->target_path == NULL) { 828*12767SJames.Kremer@Sun.COM /* NULL Target path, return error */ 829*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NULL_TARGET_PATH); 830*12767SJames.Kremer@Sun.COM } 831*12767SJames.Kremer@Sun.COM if (strncmp("SUN-GENESIS", data->product_id, 11) != 0) { 832*12767SJames.Kremer@Sun.COM /* Not a supported node, return error */ 833*12767SJames.Kremer@Sun.COM return (SES_LOG_UNSUPPORTED_HW_ERROR); 834*12767SJames.Kremer@Sun.COM } 835*12767SJames.Kremer@Sun.COM 836*12767SJames.Kremer@Sun.COM /* Try to find a valid path */ 837*12767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:ses", 838*12767SJames.Kremer@Sun.COM data->target_path); 839*12767SJames.Kremer@Sun.COM 840*12767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) { 841*12767SJames.Kremer@Sun.COM 842*12767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:0", 843*12767SJames.Kremer@Sun.COM data->target_path); 844*12767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) { 845*12767SJames.Kremer@Sun.COM /* Couldn't find a path that exists */ 846*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_BAD_TARGET_PATH); 847*12767SJames.Kremer@Sun.COM } 848*12767SJames.Kremer@Sun.COM } 849*12767SJames.Kremer@Sun.COM 850*12767SJames.Kremer@Sun.COM 851*12767SJames.Kremer@Sun.COM /* 852*12767SJames.Kremer@Sun.COM * convert nanosecond time to seconds 853*12767SJames.Kremer@Sun.COM */ 854*12767SJames.Kremer@Sun.COM poll_time = data->poll_time / 1000000000; 855*12767SJames.Kremer@Sun.COM 856*12767SJames.Kremer@Sun.COM error = nvlist_alloc(&data->log_data, NV_UNIQUE_NAME, 0); 857*12767SJames.Kremer@Sun.COM if (error != 0) { 858*12767SJames.Kremer@Sun.COM /* Couldn't alloc memory for nvlist */ 859*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NVLIST_CREATE); 860*12767SJames.Kremer@Sun.COM } 861*12767SJames.Kremer@Sun.COM 862*12767SJames.Kremer@Sun.COM 863*12767SJames.Kremer@Sun.COM /* Record the protocol used for later when an ereport is generated. */ 864*12767SJames.Kremer@Sun.COM error = nvlist_add_string(data->log_data, PROTOCOL, PROTOCOL_TYPE); 865*12767SJames.Kremer@Sun.COM if (error != 0) { 866*12767SJames.Kremer@Sun.COM nvlist_free(data->log_data); 867*12767SJames.Kremer@Sun.COM data->log_data = NULL; 868*12767SJames.Kremer@Sun.COM /* Error adding entry */ 869*12767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NVLIST_PROTOCOL); 870*12767SJames.Kremer@Sun.COM } 871*12767SJames.Kremer@Sun.COM 872*12767SJames.Kremer@Sun.COM error = gatherData(real_path, data->log_data, data->last_log_entry, 873*12767SJames.Kremer@Sun.COM poll_time, &data->number_log_entries); 874*12767SJames.Kremer@Sun.COM 875*12767SJames.Kremer@Sun.COM /* Update the size of log entries being returned */ 876*12767SJames.Kremer@Sun.COM data->size_of_log_entries = 877*12767SJames.Kremer@Sun.COM data->number_log_entries * SES_LOG_VALID_LOG_SIZE; 878*12767SJames.Kremer@Sun.COM 879*12767SJames.Kremer@Sun.COM return (error); 880*12767SJames.Kremer@Sun.COM } 881