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