libseslog.c revision e4f5a11d4a234623168c1558fcdf4341e11769e1
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * CDDL HEADER START
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * The contents of this file are subject to the terms of the
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Common Development and Distribution License (the "License").
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * You may not use this file except in compliance with the License.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * or http://www.opensolaris.org/os/licensing.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * See the License for the specific language governing permissions
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * and limitations under the License.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * When distributing Covered Code, include this CDDL HEADER in each
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * If applicable, add the following below this CDDL HEADER, with the
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * fields enclosed by brackets "[]" replaced with your own identifying
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * information: Portions Copyright [yyyy] [name of copyright owner]
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * CDDL HEADER END
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * SES Log reader library
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * This library is responsible for accessing the SES log at the target address,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * formatting and returning any log entries found.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * The data will be returned in an nvlist_t structure allocated here.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <assert.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <errno.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <fcntl.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <sys/param.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <libseslog.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <stdlib.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <string.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <sys/stat.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <unistd.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <dirent.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <sys/scsi/generic/commands.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering#include <sys/scsi/generic/status.h>
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * open the device with given device name
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic int
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringopen_device(const char *device_name)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int oflags = O_NONBLOCK | O_RDWR;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int fd;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering fd = open(device_name, oflags);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (fd < 0)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering fd = -errno;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (fd);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Initialize scsi struct
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic void
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringconstruct_scsi_pt_obj(struct uscsi_cmd *uscsi)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(uscsi, 0, sizeof (struct uscsi_cmd));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_timeout = DEF_PT_TIMEOUT;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * set control cdb of scsi structure
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic void
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringset_scsi_pt_cdb(struct uscsi_cmd *uscsi, const unsigned char *cdb,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int cdb_len)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_cdb = (char *)cdb;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt uscsi->uscsi_cdblen = cdb_len;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * initialize sense data
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic void
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringset_scsi_pt_sense(struct uscsi_cmd *uscsi, unsigned char *sense,
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt int max_sense_len)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(sense, 0, max_sense_len);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_rqbuf = (char *)sense;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_rqlen = max_sense_len;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Initialize data going to device
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic void
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringset_scsi_pt_data_in(struct uscsi_cmd *uscsi, unsigned char *dxferp,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int dxfer_len)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (dxfer_len > 0) {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt uscsi->uscsi_bufaddr = (char *)dxferp;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_buflen = dxfer_len;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering USCSI_RQENABLE;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Executes SCSI command(or at least forwards it to lower layers).
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic int
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringdo_scsi_pt(struct uscsi_cmd *uscsi, int fd, int time_secs)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (time_secs > 0)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering uscsi->uscsi_timeout = time_secs;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (ioctl(fd, USCSICMD, uscsi)) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* Took an error */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (errno);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (0);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Read log from device
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Invokes a SCSI LOG SENSE command.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Return:
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * 0 -> success
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt * SG_LIB_CAT_INVALID_OP -> Log Sense not supported,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * SG_LIB_CAT_NOT_READY -> device not ready,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * -1 -> other failure
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic int
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringread_log(int sg_fd, unsigned char *resp, int mx_resp_len)
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt{
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int res, ret;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering unsigned char logsCmdBlk[CDB_GROUP1] =
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering {SCMD_LOG_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering unsigned char sense_b[SENSE_BUFF_LEN];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering struct uscsi_cmd uscsi;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (mx_resp_len > 0xffff) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (-1);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[1] = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* pc = 1, pg_code = 0x7 (logs page) */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* (((pc << 6) & 0xc0) | (pg_code & 0x3f)) = 0x47; */
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt logsCmdBlk[2] = 0x47;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* pc = 1 current values */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[3] = 0; /* No subpage code */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[5] = 0; /* Want all logs starting from 0 */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[6] = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering logsCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering construct_scsi_pt_obj(&uscsi);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering set_scsi_pt_cdb(&uscsi, logsCmdBlk, sizeof (logsCmdBlk));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering set_scsi_pt_data_in(&uscsi, resp, mx_resp_len);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (res) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering ret = res;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering } else {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering ret = uscsi.uscsi_status;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (ret);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering}
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering/*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Save the logs by walking through the entries in the response buffer.
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * resp buffer looks like:
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * +=====-========-========-========-========-========-========-========-=====+
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |Byte | | | | | | | | |
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt * |=====+====================================================================|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 0 | reserved | page code |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 1 | Reserved |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 2 |(MSB) Page Length(n-3) |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | -- | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 3 | (LSB) |
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 4 | Log Parameter (First)(Length X) |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | -- | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | x+3 | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |n-y+1| Log Parameter (Last)(Length y) |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | -- | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | n | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * +==========================================================================+
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Log parameter field looks like:
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * +=====-========-========-========-========-========-========-========-=====+
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |Byte | | | | | | | | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |=====+====================================================================|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 0 |(MSB) Parameter Code |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | -- | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 1 | (LSB) |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt * | 2 | DU | DS | TSD | ETC | TMC | LBIN | LP |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |3 | Paramter Length(n-3) |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | 4 | Parameter Values |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | -- | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * | n | |
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * |-----+--------------------------------------------------------------------|
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringstatic int
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poetteringsave_logs(unsigned char *resp, int len, nvlist_t *log_data,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char *last_log_entry, unsigned long *seq_num_ret, int *number_log_entries)
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering{
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt int k, i;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int paramCode; /* Parameter code */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int paramLen = 0; /* Paramter length */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int pcb; /* Paramter control Byte */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering unsigned char *lpp; /* Log parameter pointer */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering unsigned char *log_str_ptr; /* ptr to ascii str returend by expander */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering unsigned long seq_num_ul = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char seq_num[10];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char log_event_type[10];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char log_code[10];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char log_level[10];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering nvlist_t *entry;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char entry_num[15];
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt int type;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering int match_found = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering long current_seq_num;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering long last_num;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char save_buffer[256];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char entry_added = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering char *s;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(seq_num, 0, sizeof (seq_num));
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering *number_log_entries = 0;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* Initial log paramter pointer to point to first log entry */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* The resp includes 4 bytes of header info and then log entries */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering lpp = &resp[0] + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering k = len;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* Find last sequence number from last log read */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (last_log_entry != NULL &&
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (strlen(last_log_entry) == SES_LOG_VALID_LOG_SIZE)) {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt (void) strncpy(seq_num, (const char *) last_log_entry +
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering SES_LOG_SEQ_NUM_START, 8);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering last_num = strtoul(seq_num, 0, 16);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* save this in case there are no new entries */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering seq_num_ul = last_num;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* First find if there are duplicate entries */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering lpp = &resp[0] + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Start walking each log entry in return buffer looking for
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * a duplicate entry.
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering for (; k > 0; k -= paramLen) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (k < 3) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Should always have at least 3 Bytes for
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * each entry
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * If not, it must be a bad record so stop
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * processing
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering nvlist_free(log_data);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering log_data = NULL;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (SES_LOG_FAILED_SHORT_LOG_PARAM_INIT);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering pcb = lpp[2];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering paramLen = lpp[3] + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * initial log_str_ptr to point to string info returned
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt * by expander
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * first 4 bytes of log
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * parameter are 2 param:
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * codes Control byte, Parameter length
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering log_str_ptr = lpp + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (paramLen > 4) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if ((pcb & 0x1) && !(pcb & 2)) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) strncpy(seq_num,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (const char *)log_str_ptr +
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering SES_LOG_SEQ_NUM_START, 8);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering current_seq_num = strtoul(seq_num, 0,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering 16);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (current_seq_num == last_num) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Check to see if this is the
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * same line
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (strncmp(
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (char *)log_str_ptr,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering last_log_entry,
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering SES_LOG_VALID_LOG_SIZE) ==
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering 0) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * Found an exact
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * match
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt lpp += paramLen;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering k -= paramLen;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering match_found = 1;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering break;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt lpp += paramLen;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (!match_found) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering lpp = &resp[0] + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering k = len;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
f7dc3ab9f43b67abcbd34062b9352ab42debec49Lennart Poettering
f7dc3ab9f43b67abcbd34062b9352ab42debec49Lennart Poettering (void) memset(log_event_type, 0, sizeof (log_event_type));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(seq_num, 0, sizeof (seq_num));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(log_code, 0, sizeof (log_code));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(save_buffer, 0, sizeof (save_buffer));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering (void) memset(log_level, 0, sizeof (log_level));
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* K will be initialized from above */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering for (; k > 0; k -= paramLen) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering if (k < 3) {
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* Should always have at least 3 Bytes for each entry */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /* If not, it must be a bad record so stop processing */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering nvlist_free(log_data);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering log_data = NULL;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering return (SES_LOG_FAILED_SHORT_LOG_PARAM);
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering }
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering paramCode = (lpp[0] << 8) + lpp[1];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering pcb = lpp[2];
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering paramLen = lpp[3] + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering /*
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * initial log_str_ptr to point to string info of the log entry
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * First 4 bytes of log entry contains param code, control
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering * byte, length
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering */
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering log_str_ptr = lpp + 4;
66cdd0f2d0670b054bd27dad16fcb5838b11dde3Lennart Poettering
/*
* Format of log str is as follows
* "%8x %8x %8x %8x %8x %8x %8x %8x",
* log_entry.log_word0, log_entry.ts_u, log_entry.ts_l,
* log_entry.seq_num, log_entry.log_code, log_entry.log_word2,
* log_entry.log_word3, log_entry.log_word4
* following example has extra spaces removed to fit in 80 char
* 40004 0 42d5f5fe 185b 630002 fd0800 50800207 e482813
*/
if (paramLen > 4) {
if ((pcb & 0x1) && !(pcb & 2)) {
(void) strncpy(save_buffer,
(const char *)log_str_ptr,
SES_LOG_VALID_LOG_SIZE);
for (i = 0; (i < 8) && (s = strtok(i ? 0 :
(char *)log_str_ptr, " ")); i++) {
char *ulp;
switch (i) {
case 0:
/* event type */
ulp = (char *)
&log_event_type;
break;
case 3:
/* sequence number */
ulp = (char *)
&seq_num;
break;
case 4:
/* log code */
ulp = (char *)
&log_code;
break;
default:
ulp = 0;
}
if (ulp) {
(void) strncpy(ulp, s, 8);
}
}
seq_num_ul = strtoul(seq_num, 0, 16);
(void) strncpy(log_level,
(const char *) log_str_ptr +
SES_LOG_LEVEL_START, 1);
/* event type is in log_event_type */
/* 4x004 = looking for x */
type = (strtoul(log_event_type, 0, 16) >> 12) &
0xf;
/*
* Check type. If type is 1, level needs to be
* changed to FATAL. If type is something other
* than 0 or 1, they are info only.
*/
if (type == 1) {
(void) strcpy(log_level, "4");
} else if (type > 1) {
/* These are not application log */
/* entries */
/* make them info only */
(void) strcpy(log_level, "0");
}
/* Add this entry to the nvlist log data */
if (nvlist_alloc(&entry,
NV_UNIQUE_NAME, 0) != 0) {
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_NV_UNIQUE);
}
if (nvlist_add_string(entry, ENTRY_LOG,
save_buffer) != 0) {
nvlist_free(entry);
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_NV_LOG);
}
if (nvlist_add_string(entry, ENTRY_CODE,
log_code) != 0) {
nvlist_free(entry);
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_NV_CODE);
}
if (nvlist_add_string(entry, ENTRY_SEVERITY,
log_level) != 0) {
nvlist_free(entry);
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_NV_SEV);
}
(void) snprintf(entry_num, sizeof (entry_num),
"%s%d", ENTRY_PREFIX, paramCode);
if (nvlist_add_nvlist(log_data, entry_num,
entry) != 0) {
nvlist_free(entry);
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_NV_ENTRY);
}
nvlist_free(entry);
entry_added = 1;
(*number_log_entries)++;
}
}
lpp += paramLen;
}
if (entry_added) {
/* Update the last log entry string with last one read */
(void) strncpy(last_log_entry, save_buffer, MAXNAMELEN);
}
*seq_num_ret = seq_num_ul;
return (0);
}
/* Setup struct to send command to device */
static void
set_scsi_pt_data_out(struct uscsi_cmd *uscsi, const unsigned char *dxferp,
int dxfer_len)
{
if (dxfer_len > 0) {
uscsi->uscsi_bufaddr = (char *)dxferp;
uscsi->uscsi_buflen = dxfer_len;
uscsi->uscsi_flags = USCSI_WRITE | USCSI_ISOLATE |
USCSI_RQENABLE;
}
}
/*
* Invokes a SCSI MODE SENSE(10) command.
* Return:
* 0 for success
* SG_LIB_CAT_INVALID_OP -> invalid opcode
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb
* SG_LIB_CAT_NOT_READY -> device not ready
* -1 -> other failure
*/
static int
sg_ll_mode_sense10(int sg_fd, void * resp, int mx_resp_len)
{
int res, ret;
unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
{SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
struct uscsi_cmd uscsi;
modesCmdBlk[1] = 0;
modesCmdBlk[2] = 0; /* page code 0 vendor specific */
modesCmdBlk[3] = 0;
modesCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff);
modesCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff);
construct_scsi_pt_obj(&uscsi);
set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
set_scsi_pt_data_in(&uscsi, (unsigned char *) resp, mx_resp_len);
res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
if (res) {
ret = res;
} else {
ret = uscsi.uscsi_status;
}
return (ret);
}
/*
* Invokes a SCSI MODE SELECT(10) command.
* Return:
* 0 for success.
* SG_LIB_CAT_INVALID_OP for invalid opcode
* SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
* SG_LIB_CAT_NOT_READY -> device not ready,
* -1 -> other failure
*/
static int
sg_ll_mode_select10(int sg_fd, void * paramp, int param_len)
{
int res, ret;
unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] =
{SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char sense_b[SENSE_BUFF_LEN];
struct uscsi_cmd uscsi;
modesCmdBlk[1] = 0;
/*
* modesCmdBlk 2 equal 0 PC 0 return current page code 0 return
* vendor specific
*/
modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
modesCmdBlk[8] = (unsigned char)(param_len & 0xff);
construct_scsi_pt_obj(&uscsi);
set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
set_scsi_pt_data_out(&uscsi, (unsigned char *) paramp, param_len);
res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
if (res) {
ret = res;
} else {
ret = uscsi.uscsi_status;
}
return (ret);
}
/*
* MODE SENSE 10 commands yield a response that has block descriptors followed
* by mode pages. In most cases users are interested in the first mode page.
* This function returns the(byte) offset of the start of the first mode page.
* Returns >= 0 is successful or -1 if failure. If there is a failure
* a message is written to err_buff.
*/
/*
* return data looks like:
* Table 92 - Mode parameter header(10)
* Bit
* Byte
* 7 6 5 4 3 2 1 0
* ----------------------------------------------------------
* 0 MSB Data length
* 1 LSB Data length
* ----------------------------------------------------------
* 2 Medium type
* ----------------------------------------------------------
* 3 Device-specific parameter
* ----------------------------------------------------------
* 4 Reserved
* ----------------------------------------------------------
* 5 Reserved
* ----------------------------------------------------------
* 6 MSB block descriptor length
* 7 LSB block descriptor length
* ----------------------------------------------------------
* block desciptors....
* -----------------------
* mode sense page:
* 0 : ps Reserved : page Code
* 1 : Page Length(n-1)
* 2-N Mode parameters
*/
static int
sg_mode_page_offset(const unsigned char *resp, int resp_len,
char *err_buff, int err_buff_len)
{
int bd_len;
int calc_len;
int offset;
if ((NULL == resp) || (resp_len < 8)) {
/* Too short of a response buffer */
return (-1);
}
calc_len = (resp[0] << 8) + resp[1] + 2;
bd_len = (resp[6] << 8) + resp[7];
/* LongLBA doesn't change this calculation */
offset = bd_len + MODE10_RESP_HDR_LEN;
if ((offset + 2) > resp_len) {
(void) snprintf(err_buff, err_buff_len,
"given response length "
"too small, offset=%d given_len=%d bd_len=%d\n",
offset, resp_len, bd_len);
offset = -1;
} else if ((offset + 2) > calc_len) {
(void) snprintf(err_buff, err_buff_len, "calculated response "
"length too small, offset=%d calc_len=%d bd_len=%d\n",
offset, calc_len, bd_len);
offset = -1;
}
return (offset);
}
/*
* Clear logs
*/
static int
clear_log(int sg_fd, unsigned long seq_num, long poll_time)
{
int res, alloc_len, off;
int md_len;
int read_in_len = 0;
unsigned char ref_md[MX_ALLOC_LEN];
char ebuff[EBUFF_SZ];
struct log_clear_control_struct clear_data;
long myhostid;
int error = 0;
(void) memset(&clear_data, 0, sizeof (clear_data));
clear_data.pageControls = 0x40;
clear_data.subpage_code = 0;
clear_data.page_lengthLower = 0x16;
myhostid = gethostid();
/* 0 -> 11 are memset to 0 */
clear_data.host_id[12] = (myhostid & 0xff000000) >> 24;
clear_data.host_id[13] = (myhostid & 0xff0000) >> 16;
clear_data.host_id[14] = (myhostid & 0xff00) >> 8;
clear_data.host_id[15] = myhostid & 0xff;
/* Timeout set to 32 seconds for now */
/* Add 5 minutes to poll time to allow for data retrievel time */
poll_time = poll_time + 300;
clear_data.timeout[0] = (poll_time & 0xff00) >> 8;
clear_data.timeout[1] = poll_time & 0xff;
clear_data.seq_clear[0] = (seq_num & 0xff000000) >> 24;
clear_data.seq_clear[1] = (seq_num & 0xff0000) >> 16;
clear_data.seq_clear[2] = (seq_num & 0xff00) >> 8;
clear_data.seq_clear[3] = (seq_num & 0xff);
read_in_len = sizeof (clear_data);
/* do MODE SENSE to fetch current values */
(void) memset(ref_md, 0, MX_ALLOC_LEN);
alloc_len = MX_ALLOC_LEN;
res = sg_ll_mode_sense10(sg_fd, ref_md, alloc_len);
if (0 != res) {
/* Error during mode sense */
error = SES_LOG_FAILED_MODE_SENSE;
return (error);
}
/* Setup mode Select to clear logs */
off = sg_mode_page_offset(ref_md, alloc_len, ebuff, EBUFF_SZ);
if (off < 0) {
/* Mode page offset error */
error = SES_LOG_FAILED_MODE_SENSE_OFFSET;
return (error);
}
md_len = (ref_md[0] << 8) + ref_md[1] + 2;
ref_md[0] = 0;
ref_md[1] = 0;
if (md_len > alloc_len) {
/* Data length to large */
error = SES_LOG_FAILED_BAD_DATA_LEN;
return (error);
}
if ((md_len - off) != read_in_len) {
/* Content length not correct */
error = SES_LOG_FAILED_BAD_CONTENT_LEN;
return (error);
}
if ((clear_data.pageControls & 0x40) != (ref_md[off] & 0x40)) {
/* reference model doesn't have use subpage format bit set */
/* Even though it should have */
/* don't send the command */
error = SES_LOG_FAILED_FORMAT_PAGE_ERROR;
return (error);
}
(void) memcpy(ref_md + off, (const void *) & clear_data,
sizeof (clear_data));
res = sg_ll_mode_select10(sg_fd, ref_md, md_len);
if (res != 0) {
error = SES_LOG_FAILED_MODE_SELECT;
return (error);
}
return (error);
}
/*
* Gather data from given device.
*/
static int
gatherData(char *device_name, nvlist_t *log_data, char *last_log_entry,
long poll_time, int *number_log_entries)
{
int sg_fd;
unsigned long seq_num;
int pg_len, resp_len, res;
unsigned char rsp_buff[MX_ALLOC_LEN];
int error;
/* Open device */
if ((sg_fd = open_device(device_name)) < 0) {
/* Failed to open device */
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_TO_OPEN_DEVICE);
}
/* Read the logs */
(void) memset(rsp_buff, 0, sizeof (rsp_buff));
resp_len = 0x8000; /* Maximum size available to read */
res = read_log(sg_fd, rsp_buff, resp_len);
if (res == 0) {
pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
if ((pg_len + 4) > resp_len) {
/* Didn't get entire response */
/* Process what we did get */
pg_len = resp_len - 4;
}
} else {
/* Some sort of Error during read of logs */
nvlist_free(log_data);
log_data = NULL;
return (SES_LOG_FAILED_TO_READ_DEVICE);
}
/* Save the logs */
error = save_logs(rsp_buff, pg_len, log_data, last_log_entry,
&seq_num, number_log_entries);
if (error != 0) {
return (error);
}
/* Clear logs */
error = clear_log(sg_fd, seq_num, poll_time);
(void) close(sg_fd);
return (error);
}
/*
* Access the SES target identified by the indicated path. Read the logs
* and return them in a nvlist.
*/
int
access_ses_log(struct ses_log_call_struct *data)
{
char real_path[MAXPATHLEN];
long poll_time;
struct stat buffer;
int error;
if (data->target_path == NULL) {
/* NULL Target path, return error */
return (SES_LOG_FAILED_NULL_TARGET_PATH);
}
if (strncmp("SUN-GENESIS", data->product_id, 11) != 0) {
/* Not a supported node, return error */
return (SES_LOG_UNSUPPORTED_HW_ERROR);
}
/* Try to find a valid path */
(void) snprintf(real_path, sizeof (real_path), "/devices%s:ses",
data->target_path);
if (stat(real_path, &buffer) != 0) {
(void) snprintf(real_path, sizeof (real_path), "/devices%s:0",
data->target_path);
if (stat(real_path, &buffer) != 0) {
/* Couldn't find a path that exists */
return (SES_LOG_FAILED_BAD_TARGET_PATH);
}
}
/*
* convert nanosecond time to seconds
*/
poll_time = data->poll_time / 1000000000;
error = nvlist_alloc(&data->log_data, NV_UNIQUE_NAME, 0);
if (error != 0) {
/* Couldn't alloc memory for nvlist */
return (SES_LOG_FAILED_NVLIST_CREATE);
}
/* Record the protocol used for later when an ereport is generated. */
error = nvlist_add_string(data->log_data, PROTOCOL, PROTOCOL_TYPE);
if (error != 0) {
nvlist_free(data->log_data);
data->log_data = NULL;
/* Error adding entry */
return (SES_LOG_FAILED_NVLIST_PROTOCOL);
}
error = gatherData(real_path, data->log_data, data->last_log_entry,
poll_time, &data->number_log_entries);
/* Update the size of log entries being returned */
data->size_of_log_entries =
data->number_log_entries * SES_LOG_VALID_LOG_SIZE;
return (error);
}