112767SJames.Kremer@Sun.COM /* 212767SJames.Kremer@Sun.COM * CDDL HEADER START 312767SJames.Kremer@Sun.COM * 412767SJames.Kremer@Sun.COM * The contents of this file are subject to the terms of the 512767SJames.Kremer@Sun.COM * Common Development and Distribution License (the "License"). 612767SJames.Kremer@Sun.COM * You may not use this file except in compliance with the License. 712767SJames.Kremer@Sun.COM * 812767SJames.Kremer@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 912767SJames.Kremer@Sun.COM * or http://www.opensolaris.org/os/licensing. 1012767SJames.Kremer@Sun.COM * See the License for the specific language governing permissions 1112767SJames.Kremer@Sun.COM * and limitations under the License. 1212767SJames.Kremer@Sun.COM * 1312767SJames.Kremer@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1412767SJames.Kremer@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1512767SJames.Kremer@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1612767SJames.Kremer@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1712767SJames.Kremer@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1812767SJames.Kremer@Sun.COM * 1912767SJames.Kremer@Sun.COM * CDDL HEADER END 2012767SJames.Kremer@Sun.COM */ 2112767SJames.Kremer@Sun.COM /* 2212767SJames.Kremer@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2312767SJames.Kremer@Sun.COM */ 2412767SJames.Kremer@Sun.COM 2512767SJames.Kremer@Sun.COM /* 2612767SJames.Kremer@Sun.COM * SES Log reader library 2712767SJames.Kremer@Sun.COM * 2812767SJames.Kremer@Sun.COM * This library is responsible for accessing the SES log at the target address, 2912767SJames.Kremer@Sun.COM * formatting and returning any log entries found. 3012767SJames.Kremer@Sun.COM * 3112767SJames.Kremer@Sun.COM * The data will be returned in an nvlist_t structure allocated here. 3212767SJames.Kremer@Sun.COM */ 3312767SJames.Kremer@Sun.COM 3412767SJames.Kremer@Sun.COM #include <assert.h> 3512767SJames.Kremer@Sun.COM #include <errno.h> 3612767SJames.Kremer@Sun.COM #include <fcntl.h> 3712767SJames.Kremer@Sun.COM #include <sys/param.h> 3812767SJames.Kremer@Sun.COM #include <libseslog.h> 3912767SJames.Kremer@Sun.COM #include <stdlib.h> 4012767SJames.Kremer@Sun.COM #include <string.h> 4112767SJames.Kremer@Sun.COM #include <sys/stat.h> 4212767SJames.Kremer@Sun.COM #include <unistd.h> 4312767SJames.Kremer@Sun.COM #include <dirent.h> 4412767SJames.Kremer@Sun.COM #include <sys/scsi/generic/commands.h> 4512767SJames.Kremer@Sun.COM #include <sys/scsi/generic/status.h> 46*12843Stodd.mckenney@oracle.com #include <sys/scsi/impl/commands.h> 4712767SJames.Kremer@Sun.COM 4812767SJames.Kremer@Sun.COM /* 4912767SJames.Kremer@Sun.COM * open the device with given device name 5012767SJames.Kremer@Sun.COM */ 5112767SJames.Kremer@Sun.COM static int 5212767SJames.Kremer@Sun.COM open_device(const char *device_name) 5312767SJames.Kremer@Sun.COM { 5412767SJames.Kremer@Sun.COM int oflags = O_NONBLOCK | O_RDWR; 5512767SJames.Kremer@Sun.COM int fd; 5612767SJames.Kremer@Sun.COM 5712767SJames.Kremer@Sun.COM fd = open(device_name, oflags); 5812767SJames.Kremer@Sun.COM if (fd < 0) 5912767SJames.Kremer@Sun.COM fd = -errno; 6012767SJames.Kremer@Sun.COM return (fd); 6112767SJames.Kremer@Sun.COM } 6212767SJames.Kremer@Sun.COM 6312767SJames.Kremer@Sun.COM /* 6412767SJames.Kremer@Sun.COM * Initialize scsi struct 6512767SJames.Kremer@Sun.COM */ 6612767SJames.Kremer@Sun.COM static void 6712767SJames.Kremer@Sun.COM construct_scsi_pt_obj(struct uscsi_cmd *uscsi) 6812767SJames.Kremer@Sun.COM { 6912767SJames.Kremer@Sun.COM (void) memset(uscsi, 0, sizeof (struct uscsi_cmd)); 7012767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = DEF_PT_TIMEOUT; 7112767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; 7212767SJames.Kremer@Sun.COM } 7312767SJames.Kremer@Sun.COM 7412767SJames.Kremer@Sun.COM /* 7512767SJames.Kremer@Sun.COM * set control cdb of scsi structure 7612767SJames.Kremer@Sun.COM */ 7712767SJames.Kremer@Sun.COM static void 7812767SJames.Kremer@Sun.COM set_scsi_pt_cdb(struct uscsi_cmd *uscsi, const unsigned char *cdb, 7912767SJames.Kremer@Sun.COM int cdb_len) 8012767SJames.Kremer@Sun.COM { 8112767SJames.Kremer@Sun.COM uscsi->uscsi_cdb = (char *)cdb; 8212767SJames.Kremer@Sun.COM uscsi->uscsi_cdblen = cdb_len; 8312767SJames.Kremer@Sun.COM } 8412767SJames.Kremer@Sun.COM 8512767SJames.Kremer@Sun.COM /* 8612767SJames.Kremer@Sun.COM * initialize sense data 8712767SJames.Kremer@Sun.COM */ 8812767SJames.Kremer@Sun.COM static void 8912767SJames.Kremer@Sun.COM set_scsi_pt_sense(struct uscsi_cmd *uscsi, unsigned char *sense, 9012767SJames.Kremer@Sun.COM int max_sense_len) 9112767SJames.Kremer@Sun.COM { 9212767SJames.Kremer@Sun.COM (void) memset(sense, 0, max_sense_len); 9312767SJames.Kremer@Sun.COM uscsi->uscsi_rqbuf = (char *)sense; 9412767SJames.Kremer@Sun.COM uscsi->uscsi_rqlen = max_sense_len; 9512767SJames.Kremer@Sun.COM } 9612767SJames.Kremer@Sun.COM 9712767SJames.Kremer@Sun.COM /* 9812767SJames.Kremer@Sun.COM * Initialize data going to device 9912767SJames.Kremer@Sun.COM */ 10012767SJames.Kremer@Sun.COM static void 10112767SJames.Kremer@Sun.COM set_scsi_pt_data_in(struct uscsi_cmd *uscsi, unsigned char *dxferp, 10212767SJames.Kremer@Sun.COM int dxfer_len) 10312767SJames.Kremer@Sun.COM { 10412767SJames.Kremer@Sun.COM if (dxfer_len > 0) { 10512767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp; 10612767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len; 10712767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | 10812767SJames.Kremer@Sun.COM USCSI_RQENABLE; 10912767SJames.Kremer@Sun.COM } 11012767SJames.Kremer@Sun.COM } 11112767SJames.Kremer@Sun.COM 11212767SJames.Kremer@Sun.COM /* 11312767SJames.Kremer@Sun.COM * Executes SCSI command(or at least forwards it to lower layers). 11412767SJames.Kremer@Sun.COM */ 11512767SJames.Kremer@Sun.COM static int 11612767SJames.Kremer@Sun.COM do_scsi_pt(struct uscsi_cmd *uscsi, int fd, int time_secs) 11712767SJames.Kremer@Sun.COM { 11812767SJames.Kremer@Sun.COM if (time_secs > 0) 11912767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = time_secs; 12012767SJames.Kremer@Sun.COM 12112767SJames.Kremer@Sun.COM if (ioctl(fd, USCSICMD, uscsi)) { 12212767SJames.Kremer@Sun.COM /* Took an error */ 12312767SJames.Kremer@Sun.COM return (errno); 12412767SJames.Kremer@Sun.COM } 12512767SJames.Kremer@Sun.COM return (0); 12612767SJames.Kremer@Sun.COM } 12712767SJames.Kremer@Sun.COM 12812767SJames.Kremer@Sun.COM 12912767SJames.Kremer@Sun.COM /* 13012767SJames.Kremer@Sun.COM * Read log from device 13112767SJames.Kremer@Sun.COM * Invokes a SCSI LOG SENSE command. 13212767SJames.Kremer@Sun.COM * Return: 13312767SJames.Kremer@Sun.COM * 0 -> success 13412767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> Log Sense not supported, 13512767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, 13612767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready, 13712767SJames.Kremer@Sun.COM * -1 -> other failure 13812767SJames.Kremer@Sun.COM */ 13912767SJames.Kremer@Sun.COM 14012767SJames.Kremer@Sun.COM static int 14112767SJames.Kremer@Sun.COM read_log(int sg_fd, unsigned char *resp, int mx_resp_len) 14212767SJames.Kremer@Sun.COM { 14312767SJames.Kremer@Sun.COM int res, ret; 14412767SJames.Kremer@Sun.COM unsigned char logsCmdBlk[CDB_GROUP1] = 14512767SJames.Kremer@Sun.COM {SCMD_LOG_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 14612767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 14712767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 14812767SJames.Kremer@Sun.COM 14912767SJames.Kremer@Sun.COM if (mx_resp_len > 0xffff) { 15012767SJames.Kremer@Sun.COM return (-1); 15112767SJames.Kremer@Sun.COM } 15212767SJames.Kremer@Sun.COM logsCmdBlk[1] = 0; 15312767SJames.Kremer@Sun.COM /* pc = 1, pg_code = 0x7 (logs page) */ 15412767SJames.Kremer@Sun.COM /* (((pc << 6) & 0xc0) | (pg_code & 0x3f)) = 0x47; */ 15512767SJames.Kremer@Sun.COM logsCmdBlk[2] = 0x47; 15612767SJames.Kremer@Sun.COM /* pc = 1 current values */ 15712767SJames.Kremer@Sun.COM logsCmdBlk[3] = 0; /* No subpage code */ 15812767SJames.Kremer@Sun.COM logsCmdBlk[5] = 0; /* Want all logs starting from 0 */ 15912767SJames.Kremer@Sun.COM logsCmdBlk[6] = 0; 16012767SJames.Kremer@Sun.COM logsCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff); 16112767SJames.Kremer@Sun.COM logsCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff); 16212767SJames.Kremer@Sun.COM 16312767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 16412767SJames.Kremer@Sun.COM 16512767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, logsCmdBlk, sizeof (logsCmdBlk)); 16612767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 16712767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, resp, mx_resp_len); 16812767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 16912767SJames.Kremer@Sun.COM if (res) { 17012767SJames.Kremer@Sun.COM ret = res; 17112767SJames.Kremer@Sun.COM } else { 17212767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 17312767SJames.Kremer@Sun.COM } 17412767SJames.Kremer@Sun.COM return (ret); 17512767SJames.Kremer@Sun.COM } 17612767SJames.Kremer@Sun.COM 17712767SJames.Kremer@Sun.COM /* 17812767SJames.Kremer@Sun.COM * Save the logs by walking through the entries in the response buffer. 17912767SJames.Kremer@Sun.COM * 18012767SJames.Kremer@Sun.COM * resp buffer looks like: 18112767SJames.Kremer@Sun.COM * 18212767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+ 18312767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 18412767SJames.Kremer@Sun.COM * |Byte | | | | | | | | | 18512767SJames.Kremer@Sun.COM * |=====+====================================================================| 18612767SJames.Kremer@Sun.COM * | 0 | reserved | page code | 18712767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 18812767SJames.Kremer@Sun.COM * | 1 | Reserved | 18912767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 19012767SJames.Kremer@Sun.COM * | 2 |(MSB) Page Length(n-3) | 19112767SJames.Kremer@Sun.COM * | -- | | 19212767SJames.Kremer@Sun.COM * | 3 | (LSB) | 19312767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 19412767SJames.Kremer@Sun.COM * | 4 | Log Parameter (First)(Length X) | 19512767SJames.Kremer@Sun.COM * | -- | | 19612767SJames.Kremer@Sun.COM * | x+3 | | 19712767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 19812767SJames.Kremer@Sun.COM * |n-y+1| Log Parameter (Last)(Length y) | 19912767SJames.Kremer@Sun.COM * | -- | | 20012767SJames.Kremer@Sun.COM * | n | | 20112767SJames.Kremer@Sun.COM * +==========================================================================+ 20212767SJames.Kremer@Sun.COM * 20312767SJames.Kremer@Sun.COM * Log parameter field looks like: 20412767SJames.Kremer@Sun.COM * 20512767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+ 20612767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 20712767SJames.Kremer@Sun.COM * |Byte | | | | | | | | | 20812767SJames.Kremer@Sun.COM * |=====+====================================================================| 20912767SJames.Kremer@Sun.COM * | 0 |(MSB) Parameter Code | 21012767SJames.Kremer@Sun.COM * | -- | | 21112767SJames.Kremer@Sun.COM * | 1 | (LSB) | 21212767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 21312767SJames.Kremer@Sun.COM * | 2 | DU | DS | TSD | ETC | TMC | LBIN | LP | 21412767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 215*12843Stodd.mckenney@oracle.com * | 3 | Parameter Length(n-3) | 21612767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 21712767SJames.Kremer@Sun.COM * | 4 | Parameter Values | 21812767SJames.Kremer@Sun.COM * | -- | | 21912767SJames.Kremer@Sun.COM * | n | | 22012767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------| 22112767SJames.Kremer@Sun.COM */ 22212767SJames.Kremer@Sun.COM 22312767SJames.Kremer@Sun.COM static int 224*12843Stodd.mckenney@oracle.com save_logs(unsigned char *resp, ses_log_call_t *data) 22512767SJames.Kremer@Sun.COM { 226*12843Stodd.mckenney@oracle.com int k; 227*12843Stodd.mckenney@oracle.com int param_code; /* Parameter code */ 228*12843Stodd.mckenney@oracle.com int param_len = 0; /* Paramter length */ 229*12843Stodd.mckenney@oracle.com unsigned char *log_param_ptr; /* Log parameter pointer */ 23012767SJames.Kremer@Sun.COM unsigned char *log_str_ptr; /* ptr to ascii str returend by expander */ 23112767SJames.Kremer@Sun.COM 232*12843Stodd.mckenney@oracle.com char log_event_type[ENTRY_MAX_SIZE]; 233*12843Stodd.mckenney@oracle.com char log_code[ENTRY_MAX_SIZE]; 234*12843Stodd.mckenney@oracle.com char log_level[ENTRY_MAX_SIZE]; 23512767SJames.Kremer@Sun.COM nvlist_t *entry; 23612767SJames.Kremer@Sun.COM char entry_num[15]; 23712767SJames.Kremer@Sun.COM int type; 23812767SJames.Kremer@Sun.COM int match_found = 0; 239*12843Stodd.mckenney@oracle.com char save_buffer[MAX_LOG_ENTRY_SZ]; 24012767SJames.Kremer@Sun.COM char entry_added = 0; 241*12843Stodd.mckenney@oracle.com int all_log_data_len; 242*12843Stodd.mckenney@oracle.com 243*12843Stodd.mckenney@oracle.com /* 244*12843Stodd.mckenney@oracle.com * Bytes 2 and 3 of response buffer contain the page length of 245*12843Stodd.mckenney@oracle.com * the log entries returned. 246*12843Stodd.mckenney@oracle.com */ 247*12843Stodd.mckenney@oracle.com all_log_data_len = SCSI_READ16(&resp[2]); 248*12843Stodd.mckenney@oracle.com 249*12843Stodd.mckenney@oracle.com /* 250*12843Stodd.mckenney@oracle.com * Initialize log parameter pointer to point to first log entry. 251*12843Stodd.mckenney@oracle.com * The resp includes 4 bytes of header info and then log entries 252*12843Stodd.mckenney@oracle.com */ 253*12843Stodd.mckenney@oracle.com log_param_ptr = &resp[0] + 4; 254*12843Stodd.mckenney@oracle.com 255*12843Stodd.mckenney@oracle.com /* 256*12843Stodd.mckenney@oracle.com * If multiple heads are reading the logs, it is possible that we 257*12843Stodd.mckenney@oracle.com * could be re-reading some of the same log entries plus some 258*12843Stodd.mckenney@oracle.com * new additional entries. Check to see if any entries in this read 259*12843Stodd.mckenney@oracle.com * contain the same log entry as the last entry we read last time. 260*12843Stodd.mckenney@oracle.com */ 261*12843Stodd.mckenney@oracle.com if (data->last_log_entry != NULL && 262*12843Stodd.mckenney@oracle.com (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE)) { 263*12843Stodd.mckenney@oracle.com /* 264*12843Stodd.mckenney@oracle.com * We have a valid log entry from a previous read log 265*12843Stodd.mckenney@oracle.com * operation. 266*12843Stodd.mckenney@oracle.com */ 26712767SJames.Kremer@Sun.COM 26812767SJames.Kremer@Sun.COM 26912767SJames.Kremer@Sun.COM /* 270*12843Stodd.mckenney@oracle.com * Start walking each log entry in response buffer looking for 27112767SJames.Kremer@Sun.COM * a duplicate entry. 27212767SJames.Kremer@Sun.COM */ 273*12843Stodd.mckenney@oracle.com for (k = 0; k < all_log_data_len; k += param_len) { 274*12843Stodd.mckenney@oracle.com /* 275*12843Stodd.mckenney@oracle.com * Calculate log entry length 276*12843Stodd.mckenney@oracle.com * Log param ptr [3] contains the log length minus the 277*12843Stodd.mckenney@oracle.com * header info which is 4 bytes so add that in. 278*12843Stodd.mckenney@oracle.com */ 279*12843Stodd.mckenney@oracle.com param_len = log_param_ptr[3] + 4; 280*12843Stodd.mckenney@oracle.com 281*12843Stodd.mckenney@oracle.com if (param_len <= 4) { 28212767SJames.Kremer@Sun.COM /* 283*12843Stodd.mckenney@oracle.com * Only header information in this entry 284*12843Stodd.mckenney@oracle.com * process next log entry 28512767SJames.Kremer@Sun.COM */ 286*12843Stodd.mckenney@oracle.com log_param_ptr += param_len; 287*12843Stodd.mckenney@oracle.com continue; 28812767SJames.Kremer@Sun.COM } 28912767SJames.Kremer@Sun.COM 29012767SJames.Kremer@Sun.COM 291*12843Stodd.mckenney@oracle.com /* 292*12843Stodd.mckenney@oracle.com * initialize log_str_ptr to point to string info 293*12843Stodd.mckenney@oracle.com * returned by expander 294*12843Stodd.mckenney@oracle.com * first 4 bytes of log parameter contains 295*12843Stodd.mckenney@oracle.com * 2 bytes of parameter code, 1 byte of Control data 296*12843Stodd.mckenney@oracle.com * and 1 byte for parameter length. Log string begins 297*12843Stodd.mckenney@oracle.com * after that so add 4 to log param ptr. 298*12843Stodd.mckenney@oracle.com */ 299*12843Stodd.mckenney@oracle.com log_str_ptr = log_param_ptr + 4; 30012767SJames.Kremer@Sun.COM 301*12843Stodd.mckenney@oracle.com /* 302*12843Stodd.mckenney@oracle.com * Check to see if this is the 303*12843Stodd.mckenney@oracle.com * same line 304*12843Stodd.mckenney@oracle.com */ 305*12843Stodd.mckenney@oracle.com if (strncmp((char *)log_str_ptr, data->last_log_entry, 306*12843Stodd.mckenney@oracle.com SES_LOG_VALID_LOG_SIZE) == 0) { 307*12843Stodd.mckenney@oracle.com /* Found an exact match */ 308*12843Stodd.mckenney@oracle.com log_param_ptr += param_len; 309*12843Stodd.mckenney@oracle.com k += param_len; 310*12843Stodd.mckenney@oracle.com match_found = 1; 311*12843Stodd.mckenney@oracle.com break; 31212767SJames.Kremer@Sun.COM } 313*12843Stodd.mckenney@oracle.com log_param_ptr += param_len; 31412767SJames.Kremer@Sun.COM } 31512767SJames.Kremer@Sun.COM } 31612767SJames.Kremer@Sun.COM if (!match_found) { 317*12843Stodd.mckenney@oracle.com log_param_ptr = &resp[0] + 4; 318*12843Stodd.mckenney@oracle.com k = 0; 319*12843Stodd.mckenney@oracle.com } 320*12843Stodd.mckenney@oracle.com if (k == all_log_data_len) { 321*12843Stodd.mckenney@oracle.com /* 322*12843Stodd.mckenney@oracle.com * Either there was no log data or we have 323*12843Stodd.mckenney@oracle.com * already read these log entries. 324*12843Stodd.mckenney@oracle.com * Just return. 325*12843Stodd.mckenney@oracle.com */ 326*12843Stodd.mckenney@oracle.com return (0); 327*12843Stodd.mckenney@oracle.com } 328*12843Stodd.mckenney@oracle.com 329*12843Stodd.mckenney@oracle.com /* Grab memory to return logs with */ 330*12843Stodd.mckenney@oracle.com if (nvlist_alloc(&data->log_data, NV_UNIQUE_NAME, 0) != 0) { 331*12843Stodd.mckenney@oracle.com /* Couldn't alloc memory for nvlist */ 332*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NVLIST_CREATE); 33312767SJames.Kremer@Sun.COM } 33412767SJames.Kremer@Sun.COM 335*12843Stodd.mckenney@oracle.com (void) memset(log_event_type, 0, sizeof (log_event_type)); 336*12843Stodd.mckenney@oracle.com (void) memset(log_code, 0, sizeof (log_code)); 337*12843Stodd.mckenney@oracle.com (void) memset(save_buffer, 0, sizeof (save_buffer)); 338*12843Stodd.mckenney@oracle.com (void) memset(log_level, 0, sizeof (log_level)); 339*12843Stodd.mckenney@oracle.com 340*12843Stodd.mckenney@oracle.com /* 341*12843Stodd.mckenney@oracle.com * Start saving new log entries 342*12843Stodd.mckenney@oracle.com * Walk the log data adding any new entries 343*12843Stodd.mckenney@oracle.com */ 34412767SJames.Kremer@Sun.COM 345*12843Stodd.mckenney@oracle.com for (; k < all_log_data_len; k += param_len) { 346*12843Stodd.mckenney@oracle.com /* 347*12843Stodd.mckenney@oracle.com * Calculate log entry length 348*12843Stodd.mckenney@oracle.com * Log ptr [3] contains the log length minus the header info 349*12843Stodd.mckenney@oracle.com * which is 4 bytes so add that in 350*12843Stodd.mckenney@oracle.com */ 351*12843Stodd.mckenney@oracle.com param_len = log_param_ptr[3] + 4; 352*12843Stodd.mckenney@oracle.com 353*12843Stodd.mckenney@oracle.com if (param_len <= 4) { 354*12843Stodd.mckenney@oracle.com /* Only header information in this entry */ 355*12843Stodd.mckenney@oracle.com /* process next log entry */ 356*12843Stodd.mckenney@oracle.com log_param_ptr += param_len; 357*12843Stodd.mckenney@oracle.com continue; 35812767SJames.Kremer@Sun.COM } 359*12843Stodd.mckenney@oracle.com 36012767SJames.Kremer@Sun.COM /* 361*12843Stodd.mckenney@oracle.com * initialize log_str_ptr to point to string info of the log 362*12843Stodd.mckenney@oracle.com * entry. First 4 bytes of log entry contains param code, 363*12843Stodd.mckenney@oracle.com * control byte, and length. Log string starts after that. 36412767SJames.Kremer@Sun.COM */ 365*12843Stodd.mckenney@oracle.com log_str_ptr = log_param_ptr + 4; 36612767SJames.Kremer@Sun.COM 36712767SJames.Kremer@Sun.COM /* 36812767SJames.Kremer@Sun.COM * Format of log str is as follows 36912767SJames.Kremer@Sun.COM * "%8x %8x %8x %8x %8x %8x %8x %8x", 37012767SJames.Kremer@Sun.COM * log_entry.log_word0, log_entry.ts_u, log_entry.ts_l, 37112767SJames.Kremer@Sun.COM * log_entry.seq_num, log_entry.log_code, log_entry.log_word2, 37212767SJames.Kremer@Sun.COM * log_entry.log_word3, log_entry.log_word4 37312767SJames.Kremer@Sun.COM * following example has extra spaces removed to fit in 80 char 37412767SJames.Kremer@Sun.COM * 40004 0 42d5f5fe 185b 630002 fd0800 50800207 e482813 37512767SJames.Kremer@Sun.COM */ 376*12843Stodd.mckenney@oracle.com 377*12843Stodd.mckenney@oracle.com (void) strncpy(save_buffer, 378*12843Stodd.mckenney@oracle.com (const char *)log_str_ptr, 379*12843Stodd.mckenney@oracle.com SES_LOG_VALID_LOG_SIZE); 380*12843Stodd.mckenney@oracle.com 381*12843Stodd.mckenney@oracle.com (void) strncpy(log_event_type, (const char *)log_str_ptr + 382*12843Stodd.mckenney@oracle.com SES_LOG_EVENT_TYPE_START, SES_LOG_SPECIFIC_ENTRY_SIZE); 383*12843Stodd.mckenney@oracle.com 384*12843Stodd.mckenney@oracle.com (void) strncpy(log_code, 385*12843Stodd.mckenney@oracle.com (const char *)log_str_ptr+SES_LOG_CODE_START, 386*12843Stodd.mckenney@oracle.com SES_LOG_SPECIFIC_ENTRY_SIZE); 387*12843Stodd.mckenney@oracle.com 388*12843Stodd.mckenney@oracle.com (void) strncpy(log_level, 389*12843Stodd.mckenney@oracle.com (const char *) log_str_ptr + 390*12843Stodd.mckenney@oracle.com SES_LOG_LEVEL_START, 1); 391*12843Stodd.mckenney@oracle.com 392*12843Stodd.mckenney@oracle.com /* event type is in log_event_type */ 393*12843Stodd.mckenney@oracle.com /* 4x004 = looking for x */ 394*12843Stodd.mckenney@oracle.com type = (strtoul(log_event_type, 0, 16) >> 12) & 0xf; 39512767SJames.Kremer@Sun.COM 396*12843Stodd.mckenney@oracle.com /* 397*12843Stodd.mckenney@oracle.com * Check type. If type is 1, level needs to be 398*12843Stodd.mckenney@oracle.com * changed to FATAL(4). If type is something other 399*12843Stodd.mckenney@oracle.com * than 0 or 1, they are info only(0). 400*12843Stodd.mckenney@oracle.com */ 401*12843Stodd.mckenney@oracle.com if (type == 1) { 402*12843Stodd.mckenney@oracle.com (void) strcpy(log_level, "4"); 403*12843Stodd.mckenney@oracle.com } else if (type > 1) { 404*12843Stodd.mckenney@oracle.com /* These are not application log */ 405*12843Stodd.mckenney@oracle.com /* entries */ 406*12843Stodd.mckenney@oracle.com /* make them info only */ 407*12843Stodd.mckenney@oracle.com (void) strcpy(log_level, "0"); 408*12843Stodd.mckenney@oracle.com } 40912767SJames.Kremer@Sun.COM 410*12843Stodd.mckenney@oracle.com /* Add this entry to the nvlist log data */ 411*12843Stodd.mckenney@oracle.com if (nvlist_alloc(&entry, NV_UNIQUE_NAME, 0) != 0) { 412*12843Stodd.mckenney@oracle.com /* Couldn't alloc space, return error */ 413*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_UNIQUE); 414*12843Stodd.mckenney@oracle.com } 41512767SJames.Kremer@Sun.COM 41612767SJames.Kremer@Sun.COM 417*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_LOG, save_buffer) != 0) { 418*12843Stodd.mckenney@oracle.com /* Error adding string, return error */ 419*12843Stodd.mckenney@oracle.com nvlist_free(entry); 420*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_LOG); 421*12843Stodd.mckenney@oracle.com } 42212767SJames.Kremer@Sun.COM 423*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_CODE, log_code) != 0) { 424*12843Stodd.mckenney@oracle.com /* Error adding string, return error */ 425*12843Stodd.mckenney@oracle.com nvlist_free(entry); 426*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_CODE); 427*12843Stodd.mckenney@oracle.com } 428*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_SEVERITY, log_level) != 0) { 429*12843Stodd.mckenney@oracle.com /* Error adding srtring, return error */ 430*12843Stodd.mckenney@oracle.com nvlist_free(entry); 431*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_SEV); 432*12843Stodd.mckenney@oracle.com } 43312767SJames.Kremer@Sun.COM 434*12843Stodd.mckenney@oracle.com param_code = SCSI_READ16(&log_param_ptr[0]); 435*12843Stodd.mckenney@oracle.com 436*12843Stodd.mckenney@oracle.com (void) snprintf(entry_num, sizeof (entry_num), 437*12843Stodd.mckenney@oracle.com "%s%d", ENTRY_PREFIX, param_code); 43812767SJames.Kremer@Sun.COM 439*12843Stodd.mckenney@oracle.com if (nvlist_add_nvlist(data->log_data, entry_num, entry) != 0) { 440*12843Stodd.mckenney@oracle.com /* Error adding nvlist, return error */ 441*12843Stodd.mckenney@oracle.com nvlist_free(entry); 442*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_ENTRY); 443*12843Stodd.mckenney@oracle.com } 444*12843Stodd.mckenney@oracle.com nvlist_free(entry); 44512767SJames.Kremer@Sun.COM 446*12843Stodd.mckenney@oracle.com entry_added = 1; 447*12843Stodd.mckenney@oracle.com (data->number_log_entries)++; 44812767SJames.Kremer@Sun.COM 449*12843Stodd.mckenney@oracle.com log_param_ptr += param_len; 45012767SJames.Kremer@Sun.COM 45112767SJames.Kremer@Sun.COM } 45212767SJames.Kremer@Sun.COM if (entry_added) { 45312767SJames.Kremer@Sun.COM /* Update the last log entry string with last one read */ 454*12843Stodd.mckenney@oracle.com (void) strncpy(data->last_log_entry, save_buffer, MAXNAMELEN); 45512767SJames.Kremer@Sun.COM } 45612767SJames.Kremer@Sun.COM return (0); 45712767SJames.Kremer@Sun.COM } 45812767SJames.Kremer@Sun.COM 45912767SJames.Kremer@Sun.COM 46012767SJames.Kremer@Sun.COM 46112767SJames.Kremer@Sun.COM /* Setup struct to send command to device */ 46212767SJames.Kremer@Sun.COM static void 46312767SJames.Kremer@Sun.COM set_scsi_pt_data_out(struct uscsi_cmd *uscsi, const unsigned char *dxferp, 46412767SJames.Kremer@Sun.COM int dxfer_len) 46512767SJames.Kremer@Sun.COM { 46612767SJames.Kremer@Sun.COM if (dxfer_len > 0) { 46712767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp; 46812767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len; 46912767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_WRITE | USCSI_ISOLATE | 47012767SJames.Kremer@Sun.COM USCSI_RQENABLE; 47112767SJames.Kremer@Sun.COM } 47212767SJames.Kremer@Sun.COM } 47312767SJames.Kremer@Sun.COM 47412767SJames.Kremer@Sun.COM /* 47512767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SENSE(10) command. 47612767SJames.Kremer@Sun.COM * Return: 47712767SJames.Kremer@Sun.COM * 0 for success 47812767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> invalid opcode 47912767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb 48012767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready 48112767SJames.Kremer@Sun.COM * -1 -> other failure 48212767SJames.Kremer@Sun.COM */ 48312767SJames.Kremer@Sun.COM 48412767SJames.Kremer@Sun.COM static int 48512767SJames.Kremer@Sun.COM sg_ll_mode_sense10(int sg_fd, void * resp, int mx_resp_len) 48612767SJames.Kremer@Sun.COM { 48712767SJames.Kremer@Sun.COM int res, ret; 48812767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = 48912767SJames.Kremer@Sun.COM {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 49012767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 49112767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 49212767SJames.Kremer@Sun.COM 49312767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0; 49412767SJames.Kremer@Sun.COM modesCmdBlk[2] = 0; /* page code 0 vendor specific */ 49512767SJames.Kremer@Sun.COM modesCmdBlk[3] = 0; 49612767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff); 49712767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff); 49812767SJames.Kremer@Sun.COM 49912767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 50012767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk)); 50112767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 50212767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, (unsigned char *) resp, mx_resp_len); 50312767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 50412767SJames.Kremer@Sun.COM if (res) { 50512767SJames.Kremer@Sun.COM ret = res; 50612767SJames.Kremer@Sun.COM } else { 50712767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 50812767SJames.Kremer@Sun.COM } 50912767SJames.Kremer@Sun.COM return (ret); 51012767SJames.Kremer@Sun.COM } 51112767SJames.Kremer@Sun.COM 51212767SJames.Kremer@Sun.COM /* 51312767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SELECT(10) command. 51412767SJames.Kremer@Sun.COM * Return: 51512767SJames.Kremer@Sun.COM * 0 for success. 51612767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP for invalid opcode 51712767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, 51812767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready, 51912767SJames.Kremer@Sun.COM * -1 -> other failure 52012767SJames.Kremer@Sun.COM */ 52112767SJames.Kremer@Sun.COM static int 52212767SJames.Kremer@Sun.COM sg_ll_mode_select10(int sg_fd, void * paramp, int param_len) 52312767SJames.Kremer@Sun.COM { 52412767SJames.Kremer@Sun.COM int res, ret; 52512767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] = 52612767SJames.Kremer@Sun.COM {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 52712767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN]; 52812767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi; 52912767SJames.Kremer@Sun.COM 53012767SJames.Kremer@Sun.COM 53112767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0; 53212767SJames.Kremer@Sun.COM /* 533*12843Stodd.mckenney@oracle.com * modesCmdBlk 2 equal 0 PC 0 return current page code 0 return 53412767SJames.Kremer@Sun.COM * vendor specific 53512767SJames.Kremer@Sun.COM */ 53612767SJames.Kremer@Sun.COM 53712767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); 53812767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char)(param_len & 0xff); 53912767SJames.Kremer@Sun.COM 54012767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi); 54112767SJames.Kremer@Sun.COM 54212767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk)); 54312767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b)); 54412767SJames.Kremer@Sun.COM set_scsi_pt_data_out(&uscsi, (unsigned char *) paramp, param_len); 54512767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT); 54612767SJames.Kremer@Sun.COM if (res) { 54712767SJames.Kremer@Sun.COM ret = res; 54812767SJames.Kremer@Sun.COM } else { 54912767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status; 55012767SJames.Kremer@Sun.COM } 55112767SJames.Kremer@Sun.COM return (ret); 55212767SJames.Kremer@Sun.COM } 55312767SJames.Kremer@Sun.COM 55412767SJames.Kremer@Sun.COM 55512767SJames.Kremer@Sun.COM 55612767SJames.Kremer@Sun.COM /* 55712767SJames.Kremer@Sun.COM * MODE SENSE 10 commands yield a response that has block descriptors followed 55812767SJames.Kremer@Sun.COM * by mode pages. In most cases users are interested in the first mode page. 55912767SJames.Kremer@Sun.COM * This function returns the(byte) offset of the start of the first mode page. 56012767SJames.Kremer@Sun.COM * Returns >= 0 is successful or -1 if failure. If there is a failure 56112767SJames.Kremer@Sun.COM * a message is written to err_buff. 56212767SJames.Kremer@Sun.COM */ 56312767SJames.Kremer@Sun.COM 56412767SJames.Kremer@Sun.COM /* 56512767SJames.Kremer@Sun.COM * return data looks like: 56612767SJames.Kremer@Sun.COM * Table 92 - Mode parameter header(10) 56712767SJames.Kremer@Sun.COM * Bit 56812767SJames.Kremer@Sun.COM * Byte 56912767SJames.Kremer@Sun.COM * 7 6 5 4 3 2 1 0 57012767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 57112767SJames.Kremer@Sun.COM * 0 MSB Data length 57212767SJames.Kremer@Sun.COM * 1 LSB Data length 57312767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 57412767SJames.Kremer@Sun.COM * 2 Medium type 57512767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 57612767SJames.Kremer@Sun.COM * 3 Device-specific parameter 57712767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 57812767SJames.Kremer@Sun.COM * 4 Reserved 57912767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 58012767SJames.Kremer@Sun.COM * 5 Reserved 58112767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 58212767SJames.Kremer@Sun.COM * 6 MSB block descriptor length 58312767SJames.Kremer@Sun.COM * 7 LSB block descriptor length 58412767SJames.Kremer@Sun.COM * ---------------------------------------------------------- 58512767SJames.Kremer@Sun.COM * block desciptors.... 58612767SJames.Kremer@Sun.COM * ----------------------- 58712767SJames.Kremer@Sun.COM * mode sense page: 58812767SJames.Kremer@Sun.COM * 0 : ps Reserved : page Code 58912767SJames.Kremer@Sun.COM * 1 : Page Length(n-1) 59012767SJames.Kremer@Sun.COM * 2-N Mode parameters 59112767SJames.Kremer@Sun.COM */ 59212767SJames.Kremer@Sun.COM static int 593*12843Stodd.mckenney@oracle.com sg_mode_page_offset(const unsigned char *resp, int resp_len) 59412767SJames.Kremer@Sun.COM { 59512767SJames.Kremer@Sun.COM int bd_len; 59612767SJames.Kremer@Sun.COM int calc_len; 59712767SJames.Kremer@Sun.COM int offset; 59812767SJames.Kremer@Sun.COM 59912767SJames.Kremer@Sun.COM if ((NULL == resp) || (resp_len < 8)) { 60012767SJames.Kremer@Sun.COM /* Too short of a response buffer */ 60112767SJames.Kremer@Sun.COM return (-1); 60212767SJames.Kremer@Sun.COM } 60312767SJames.Kremer@Sun.COM 60412767SJames.Kremer@Sun.COM calc_len = (resp[0] << 8) + resp[1] + 2; 60512767SJames.Kremer@Sun.COM bd_len = (resp[6] << 8) + resp[7]; 60612767SJames.Kremer@Sun.COM 60712767SJames.Kremer@Sun.COM /* LongLBA doesn't change this calculation */ 60812767SJames.Kremer@Sun.COM offset = bd_len + MODE10_RESP_HDR_LEN; 60912767SJames.Kremer@Sun.COM 61012767SJames.Kremer@Sun.COM if ((offset + 2) > resp_len) { 611*12843Stodd.mckenney@oracle.com /* Given response length to small */ 61212767SJames.Kremer@Sun.COM offset = -1; 61312767SJames.Kremer@Sun.COM } else if ((offset + 2) > calc_len) { 614*12843Stodd.mckenney@oracle.com /* Calculated response length too small */ 61512767SJames.Kremer@Sun.COM offset = -1; 61612767SJames.Kremer@Sun.COM } 61712767SJames.Kremer@Sun.COM return (offset); 61812767SJames.Kremer@Sun.COM } 61912767SJames.Kremer@Sun.COM 62012767SJames.Kremer@Sun.COM /* 62112767SJames.Kremer@Sun.COM * Clear logs 62212767SJames.Kremer@Sun.COM */ 62312767SJames.Kremer@Sun.COM static int 624*12843Stodd.mckenney@oracle.com clear_log(int sg_fd, ses_log_call_t *data) 62512767SJames.Kremer@Sun.COM { 62612767SJames.Kremer@Sun.COM 62712767SJames.Kremer@Sun.COM int res, alloc_len, off; 62812767SJames.Kremer@Sun.COM int md_len; 62912767SJames.Kremer@Sun.COM int read_in_len = 0; 630*12843Stodd.mckenney@oracle.com unsigned char ref_md[MAX_ALLOC_LEN]; 63112767SJames.Kremer@Sun.COM struct log_clear_control_struct clear_data; 63212767SJames.Kremer@Sun.COM long myhostid; 63312767SJames.Kremer@Sun.COM int error = 0; 634*12843Stodd.mckenney@oracle.com long poll_time; 635*12843Stodd.mckenney@oracle.com char seq_num_str[10]; 636*12843Stodd.mckenney@oracle.com unsigned long seq_num = 0; 63712767SJames.Kremer@Sun.COM 63812767SJames.Kremer@Sun.COM (void) memset(&clear_data, 0, sizeof (clear_data)); 63912767SJames.Kremer@Sun.COM 64012767SJames.Kremer@Sun.COM clear_data.pageControls = 0x40; 64112767SJames.Kremer@Sun.COM clear_data.subpage_code = 0; 64212767SJames.Kremer@Sun.COM clear_data.page_lengthLower = 0x16; 64312767SJames.Kremer@Sun.COM 64412767SJames.Kremer@Sun.COM myhostid = gethostid(); 64512767SJames.Kremer@Sun.COM /* 0 -> 11 are memset to 0 */ 64612767SJames.Kremer@Sun.COM clear_data.host_id[12] = (myhostid & 0xff000000) >> 24; 64712767SJames.Kremer@Sun.COM clear_data.host_id[13] = (myhostid & 0xff0000) >> 16; 64812767SJames.Kremer@Sun.COM clear_data.host_id[14] = (myhostid & 0xff00) >> 8; 64912767SJames.Kremer@Sun.COM clear_data.host_id[15] = myhostid & 0xff; 65012767SJames.Kremer@Sun.COM 651*12843Stodd.mckenney@oracle.com /* 652*12843Stodd.mckenney@oracle.com * convert nanosecond time to seconds 653*12843Stodd.mckenney@oracle.com */ 654*12843Stodd.mckenney@oracle.com poll_time = data->poll_time / 1000000000; 655*12843Stodd.mckenney@oracle.com /* Add 5 minutes to poll time to allow for data retrieval time */ 65612767SJames.Kremer@Sun.COM poll_time = poll_time + 300; 65712767SJames.Kremer@Sun.COM clear_data.timeout[0] = (poll_time & 0xff00) >> 8; 65812767SJames.Kremer@Sun.COM clear_data.timeout[1] = poll_time & 0xff; 65912767SJames.Kremer@Sun.COM 660*12843Stodd.mckenney@oracle.com /* 661*12843Stodd.mckenney@oracle.com * retrieve the last read sequence number from the last 662*12843Stodd.mckenney@oracle.com * log entry read. 663*12843Stodd.mckenney@oracle.com */ 664*12843Stodd.mckenney@oracle.com if (data->last_log_entry != NULL && 665*12843Stodd.mckenney@oracle.com (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE)) { 666*12843Stodd.mckenney@oracle.com /* 667*12843Stodd.mckenney@oracle.com * We have a valid log entry from a previous read log 668*12843Stodd.mckenney@oracle.com * operation. 669*12843Stodd.mckenney@oracle.com */ 670*12843Stodd.mckenney@oracle.com (void) strncpy(seq_num_str, 671*12843Stodd.mckenney@oracle.com (const char *) data->last_log_entry + 672*12843Stodd.mckenney@oracle.com SES_LOG_SEQ_NUM_START, 8); 673*12843Stodd.mckenney@oracle.com seq_num = strtoul(seq_num_str, 0, 16); 674*12843Stodd.mckenney@oracle.com } 67512767SJames.Kremer@Sun.COM clear_data.seq_clear[0] = (seq_num & 0xff000000) >> 24; 67612767SJames.Kremer@Sun.COM clear_data.seq_clear[1] = (seq_num & 0xff0000) >> 16; 67712767SJames.Kremer@Sun.COM clear_data.seq_clear[2] = (seq_num & 0xff00) >> 8; 67812767SJames.Kremer@Sun.COM clear_data.seq_clear[3] = (seq_num & 0xff); 67912767SJames.Kremer@Sun.COM 68012767SJames.Kremer@Sun.COM read_in_len = sizeof (clear_data); 68112767SJames.Kremer@Sun.COM 68212767SJames.Kremer@Sun.COM 68312767SJames.Kremer@Sun.COM /* do MODE SENSE to fetch current values */ 684*12843Stodd.mckenney@oracle.com (void) memset(ref_md, 0, MAX_ALLOC_LEN); 685*12843Stodd.mckenney@oracle.com alloc_len = MAX_ALLOC_LEN; 68612767SJames.Kremer@Sun.COM 68712767SJames.Kremer@Sun.COM 68812767SJames.Kremer@Sun.COM res = sg_ll_mode_sense10(sg_fd, ref_md, alloc_len); 68912767SJames.Kremer@Sun.COM if (0 != res) { 69012767SJames.Kremer@Sun.COM /* Error during mode sense */ 69112767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE; 69212767SJames.Kremer@Sun.COM return (error); 69312767SJames.Kremer@Sun.COM } 69412767SJames.Kremer@Sun.COM 69512767SJames.Kremer@Sun.COM /* Setup mode Select to clear logs */ 696*12843Stodd.mckenney@oracle.com off = sg_mode_page_offset(ref_md, alloc_len); 69712767SJames.Kremer@Sun.COM if (off < 0) { 69812767SJames.Kremer@Sun.COM /* Mode page offset error */ 69912767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE_OFFSET; 70012767SJames.Kremer@Sun.COM return (error); 70112767SJames.Kremer@Sun.COM } 70212767SJames.Kremer@Sun.COM md_len = (ref_md[0] << 8) + ref_md[1] + 2; 70312767SJames.Kremer@Sun.COM 70412767SJames.Kremer@Sun.COM ref_md[0] = 0; 70512767SJames.Kremer@Sun.COM ref_md[1] = 0; 70612767SJames.Kremer@Sun.COM 70712767SJames.Kremer@Sun.COM if (md_len > alloc_len) { 70812767SJames.Kremer@Sun.COM /* Data length to large */ 70912767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_DATA_LEN; 71012767SJames.Kremer@Sun.COM return (error); 71112767SJames.Kremer@Sun.COM } 71212767SJames.Kremer@Sun.COM 71312767SJames.Kremer@Sun.COM if ((md_len - off) != read_in_len) { 71412767SJames.Kremer@Sun.COM /* Content length not correct */ 71512767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_CONTENT_LEN; 71612767SJames.Kremer@Sun.COM return (error); 71712767SJames.Kremer@Sun.COM } 71812767SJames.Kremer@Sun.COM 71912767SJames.Kremer@Sun.COM if ((clear_data.pageControls & 0x40) != (ref_md[off] & 0x40)) { 72012767SJames.Kremer@Sun.COM /* reference model doesn't have use subpage format bit set */ 72112767SJames.Kremer@Sun.COM /* Even though it should have */ 72212767SJames.Kremer@Sun.COM /* don't send the command */ 723*12843Stodd.mckenney@oracle.com error = SES_LOG_FAILED_FORMAT_PAGE_ERR; 72412767SJames.Kremer@Sun.COM return (error); 72512767SJames.Kremer@Sun.COM } 72612767SJames.Kremer@Sun.COM 727*12843Stodd.mckenney@oracle.com (void) memcpy(ref_md + off, (const void *) &clear_data, 72812767SJames.Kremer@Sun.COM sizeof (clear_data)); 72912767SJames.Kremer@Sun.COM 73012767SJames.Kremer@Sun.COM res = sg_ll_mode_select10(sg_fd, ref_md, md_len); 73112767SJames.Kremer@Sun.COM if (res != 0) { 73212767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SELECT; 73312767SJames.Kremer@Sun.COM return (error); 73412767SJames.Kremer@Sun.COM } 73512767SJames.Kremer@Sun.COM 73612767SJames.Kremer@Sun.COM return (error); 73712767SJames.Kremer@Sun.COM } 73812767SJames.Kremer@Sun.COM /* 73912767SJames.Kremer@Sun.COM * Gather data from given device. 74012767SJames.Kremer@Sun.COM */ 74112767SJames.Kremer@Sun.COM static int 742*12843Stodd.mckenney@oracle.com gather_data(char *device_name, ses_log_call_t *data) 74312767SJames.Kremer@Sun.COM { 74412767SJames.Kremer@Sun.COM int sg_fd; 745*12843Stodd.mckenney@oracle.com int resp_len, res; 746*12843Stodd.mckenney@oracle.com unsigned char rsp_buff[MAX_ALLOC_LEN]; 74712767SJames.Kremer@Sun.COM int error; 74812767SJames.Kremer@Sun.COM 74912767SJames.Kremer@Sun.COM /* Open device */ 75012767SJames.Kremer@Sun.COM if ((sg_fd = open_device(device_name)) < 0) { 75112767SJames.Kremer@Sun.COM /* Failed to open device */ 75212767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_OPEN_DEVICE); 75312767SJames.Kremer@Sun.COM } 75412767SJames.Kremer@Sun.COM 75512767SJames.Kremer@Sun.COM /* Read the logs */ 75612767SJames.Kremer@Sun.COM (void) memset(rsp_buff, 0, sizeof (rsp_buff)); 75712767SJames.Kremer@Sun.COM resp_len = 0x8000; /* Maximum size available to read */ 75812767SJames.Kremer@Sun.COM res = read_log(sg_fd, rsp_buff, resp_len); 75912767SJames.Kremer@Sun.COM 760*12843Stodd.mckenney@oracle.com if (res != 0) { 76112767SJames.Kremer@Sun.COM /* Some sort of Error during read of logs */ 762*12843Stodd.mckenney@oracle.com (void) close(sg_fd); 76312767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_READ_DEVICE); 76412767SJames.Kremer@Sun.COM } 76512767SJames.Kremer@Sun.COM 76612767SJames.Kremer@Sun.COM /* Save the logs */ 767*12843Stodd.mckenney@oracle.com error = save_logs(rsp_buff, data); 76812767SJames.Kremer@Sun.COM if (error != 0) { 769*12843Stodd.mckenney@oracle.com (void) close(sg_fd); 77012767SJames.Kremer@Sun.COM return (error); 77112767SJames.Kremer@Sun.COM } 772*12843Stodd.mckenney@oracle.com /* Clear the logs */ 773*12843Stodd.mckenney@oracle.com error = clear_log(sg_fd, data); 77412767SJames.Kremer@Sun.COM 77512767SJames.Kremer@Sun.COM (void) close(sg_fd); 77612767SJames.Kremer@Sun.COM 77712767SJames.Kremer@Sun.COM return (error); 77812767SJames.Kremer@Sun.COM } 77912767SJames.Kremer@Sun.COM 78012767SJames.Kremer@Sun.COM /* 78112767SJames.Kremer@Sun.COM * Access the SES target identified by the indicated path. Read the logs 78212767SJames.Kremer@Sun.COM * and return them in a nvlist. 78312767SJames.Kremer@Sun.COM */ 78412767SJames.Kremer@Sun.COM int 785*12843Stodd.mckenney@oracle.com access_ses_log(ses_log_call_t *data) 78612767SJames.Kremer@Sun.COM { 78712767SJames.Kremer@Sun.COM char real_path[MAXPATHLEN]; 78812767SJames.Kremer@Sun.COM struct stat buffer; 78912767SJames.Kremer@Sun.COM int error; 79012767SJames.Kremer@Sun.COM 791*12843Stodd.mckenney@oracle.com /* Initialize return data */ 792*12843Stodd.mckenney@oracle.com data->log_data = NULL; 793*12843Stodd.mckenney@oracle.com data->number_log_entries = 0; 794*12843Stodd.mckenney@oracle.com 79512767SJames.Kremer@Sun.COM if (data->target_path == NULL) { 79612767SJames.Kremer@Sun.COM /* NULL Target path, return error */ 79712767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NULL_TARGET_PATH); 79812767SJames.Kremer@Sun.COM } 79912767SJames.Kremer@Sun.COM 80012767SJames.Kremer@Sun.COM /* Try to find a valid path */ 80112767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:ses", 80212767SJames.Kremer@Sun.COM data->target_path); 80312767SJames.Kremer@Sun.COM 80412767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) { 80512767SJames.Kremer@Sun.COM 80612767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:0", 80712767SJames.Kremer@Sun.COM data->target_path); 80812767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) { 80912767SJames.Kremer@Sun.COM /* Couldn't find a path that exists */ 81012767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_BAD_TARGET_PATH); 81112767SJames.Kremer@Sun.COM } 81212767SJames.Kremer@Sun.COM } 81312767SJames.Kremer@Sun.COM 814*12843Stodd.mckenney@oracle.com error = gather_data(real_path, data); 81512767SJames.Kremer@Sun.COM 81612767SJames.Kremer@Sun.COM /* Update the size of log entries being returned */ 81712767SJames.Kremer@Sun.COM data->size_of_log_entries = 81812767SJames.Kremer@Sun.COM data->number_log_entries * SES_LOG_VALID_LOG_SIZE; 81912767SJames.Kremer@Sun.COM 82012767SJames.Kremer@Sun.COM return (error); 82112767SJames.Kremer@Sun.COM } 822