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>
465cf8276bSTodd 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
open_device(const char * device_name)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
construct_scsi_pt_obj(struct uscsi_cmd * uscsi)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
set_scsi_pt_cdb(struct uscsi_cmd * uscsi,const unsigned char * cdb,int cdb_len)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
set_scsi_pt_sense(struct uscsi_cmd * uscsi,unsigned char * sense,int max_sense_len)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
set_scsi_pt_data_in(struct uscsi_cmd * uscsi,unsigned char * dxferp,int dxfer_len)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
do_scsi_pt(struct uscsi_cmd * uscsi,int fd,int time_secs)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
read_log(int sg_fd,unsigned char * resp,int mx_resp_len)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 * |-----+--------------------------------------------------------------------|
2155cf8276bSTodd 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
save_logs(unsigned char * resp,ses_log_call_t * data)2245cf8276bSTodd McKenney save_logs(unsigned char *resp, ses_log_call_t *data)
225e4f5a11dSJames Kremer {
2265cf8276bSTodd McKenney int k;
2275cf8276bSTodd McKenney int param_code; /* Parameter code */
2285cf8276bSTodd McKenney int param_len = 0; /* Paramter length */
2295cf8276bSTodd 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
2325cf8276bSTodd McKenney char log_code[ENTRY_MAX_SIZE];
2335cf8276bSTodd McKenney char log_level[ENTRY_MAX_SIZE];
234e4f5a11dSJames Kremer nvlist_t *entry;
235e4f5a11dSJames Kremer char entry_num[15];
236e4f5a11dSJames Kremer int match_found = 0;
2375cf8276bSTodd McKenney char save_buffer[MAX_LOG_ENTRY_SZ];
238e4f5a11dSJames Kremer char entry_added = 0;
2395cf8276bSTodd McKenney int all_log_data_len;
240e4f5a11dSJames Kremer
241e4f5a11dSJames Kremer /*
2425cf8276bSTodd McKenney * Bytes 2 and 3 of response buffer contain the page length of
2435cf8276bSTodd McKenney * the log entries returned.
2445cf8276bSTodd McKenney */
2455cf8276bSTodd McKenney all_log_data_len = SCSI_READ16(&resp[2]);
2465cf8276bSTodd McKenney
2475cf8276bSTodd McKenney /*
2485cf8276bSTodd McKenney * Initialize log parameter pointer to point to first log entry.
2495cf8276bSTodd McKenney * The resp includes 4 bytes of header info and then log entries
2505cf8276bSTodd McKenney */
2515cf8276bSTodd McKenney log_param_ptr = &resp[0] + 4;
2525cf8276bSTodd McKenney
2535cf8276bSTodd McKenney /*
2545cf8276bSTodd McKenney * If multiple heads are reading the logs, it is possible that we
2555cf8276bSTodd McKenney * could be re-reading some of the same log entries plus some
2565cf8276bSTodd McKenney * new additional entries. Check to see if any entries in this read
2575cf8276bSTodd McKenney * contain the same log entry as the last entry we read last time.
2585cf8276bSTodd McKenney */
259*c56822beSToomas Soome if (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE) {
2605cf8276bSTodd McKenney /*
2615cf8276bSTodd McKenney * We have a valid log entry from a previous read log
2625cf8276bSTodd McKenney * operation.
2635cf8276bSTodd McKenney */
2645cf8276bSTodd McKenney
2655cf8276bSTodd McKenney
2665cf8276bSTodd McKenney /*
2675cf8276bSTodd McKenney * Start walking each log entry in response buffer looking for
268e4f5a11dSJames Kremer * a duplicate entry.
269e4f5a11dSJames Kremer */
2705cf8276bSTodd McKenney for (k = 0; k < all_log_data_len; k += param_len) {
271e4f5a11dSJames Kremer /*
2725cf8276bSTodd McKenney * Calculate log entry length
2735cf8276bSTodd McKenney * Log param ptr [3] contains the log length minus the
2745cf8276bSTodd McKenney * header info which is 4 bytes so add that in.
275e4f5a11dSJames Kremer */
2765cf8276bSTodd McKenney param_len = log_param_ptr[3] + 4;
2775cf8276bSTodd McKenney
2785cf8276bSTodd McKenney if (param_len <= 4) {
2795cf8276bSTodd McKenney /*
2805cf8276bSTodd McKenney * Only header information in this entry
2815cf8276bSTodd McKenney * process next log entry
2825cf8276bSTodd McKenney */
2835cf8276bSTodd McKenney log_param_ptr += param_len;
2845cf8276bSTodd McKenney continue;
285e4f5a11dSJames Kremer }
2865cf8276bSTodd McKenney
2875cf8276bSTodd McKenney
288e4f5a11dSJames Kremer /*
2895cf8276bSTodd McKenney * initialize log_str_ptr to point to string info
2905cf8276bSTodd McKenney * returned by expander
2915cf8276bSTodd McKenney * first 4 bytes of log parameter contains
2925cf8276bSTodd McKenney * 2 bytes of parameter code, 1 byte of Control data
2935cf8276bSTodd McKenney * and 1 byte for parameter length. Log string begins
2945cf8276bSTodd McKenney * after that so add 4 to log param ptr.
295e4f5a11dSJames Kremer */
2965cf8276bSTodd McKenney log_str_ptr = log_param_ptr + 4;
297e4f5a11dSJames Kremer
298e4f5a11dSJames Kremer /*
299e4f5a11dSJames Kremer * Check to see if this is the
300e4f5a11dSJames Kremer * same line
301e4f5a11dSJames Kremer */
3025cf8276bSTodd McKenney if (strncmp((char *)log_str_ptr, data->last_log_entry,
3035cf8276bSTodd McKenney SES_LOG_VALID_LOG_SIZE) == 0) {
3045cf8276bSTodd McKenney /* Found an exact match */
3055cf8276bSTodd McKenney log_param_ptr += param_len;
3065cf8276bSTodd McKenney k += param_len;
307e4f5a11dSJames Kremer match_found = 1;
308e4f5a11dSJames Kremer break;
309e4f5a11dSJames Kremer }
3105cf8276bSTodd McKenney log_param_ptr += param_len;
311e4f5a11dSJames Kremer }
312e4f5a11dSJames Kremer }
313e4f5a11dSJames Kremer if (!match_found) {
3145cf8276bSTodd McKenney log_param_ptr = &resp[0] + 4;
3155cf8276bSTodd McKenney k = 0;
3165cf8276bSTodd McKenney }
3175cf8276bSTodd McKenney if (k == all_log_data_len) {
3185cf8276bSTodd McKenney /*
3195cf8276bSTodd McKenney * Either there was no log data or we have
3205cf8276bSTodd McKenney * already read these log entries.
3215cf8276bSTodd McKenney * Just return.
3225cf8276bSTodd McKenney */
3235cf8276bSTodd McKenney return (0);
3245cf8276bSTodd McKenney }
3255cf8276bSTodd McKenney
3265cf8276bSTodd McKenney /* Grab memory to return logs with */
3275cf8276bSTodd McKenney if (nvlist_alloc(&data->log_data, NV_UNIQUE_NAME, 0) != 0) {
3285cf8276bSTodd McKenney /* Couldn't alloc memory for nvlist */
3295cf8276bSTodd McKenney return (SES_LOG_FAILED_NVLIST_CREATE);
330e4f5a11dSJames Kremer }
331e4f5a11dSJames Kremer
332e4f5a11dSJames Kremer (void) memset(log_code, 0, sizeof (log_code));
333e4f5a11dSJames Kremer (void) memset(save_buffer, 0, sizeof (save_buffer));
334e4f5a11dSJames Kremer (void) memset(log_level, 0, sizeof (log_level));
335e4f5a11dSJames Kremer
336e4f5a11dSJames Kremer /*
3375cf8276bSTodd McKenney * Start saving new log entries
3385cf8276bSTodd McKenney * Walk the log data adding any new entries
339e4f5a11dSJames Kremer */
3405cf8276bSTodd McKenney
3415cf8276bSTodd McKenney for (; k < all_log_data_len; k += param_len) {
3425cf8276bSTodd McKenney /*
3435cf8276bSTodd McKenney * Calculate log entry length
3445cf8276bSTodd McKenney * Log ptr [3] contains the log length minus the header info
3455cf8276bSTodd McKenney * which is 4 bytes so add that in
3465cf8276bSTodd McKenney */
3475cf8276bSTodd McKenney param_len = log_param_ptr[3] + 4;
3485cf8276bSTodd McKenney
3495cf8276bSTodd McKenney if (param_len <= 4) {
3505cf8276bSTodd McKenney /* Only header information in this entry */
3515cf8276bSTodd McKenney /* process next log entry */
3525cf8276bSTodd McKenney log_param_ptr += param_len;
3535cf8276bSTodd McKenney continue;
3545cf8276bSTodd McKenney }
3555cf8276bSTodd McKenney
3565cf8276bSTodd McKenney /*
3575cf8276bSTodd McKenney * initialize log_str_ptr to point to string info of the log
3585cf8276bSTodd McKenney * entry. First 4 bytes of log entry contains param code,
3595cf8276bSTodd McKenney * control byte, and length. Log string starts after that.
3605cf8276bSTodd McKenney */
3615cf8276bSTodd McKenney log_str_ptr = log_param_ptr + 4;
362e4f5a11dSJames Kremer
363e4f5a11dSJames Kremer /*
364e4f5a11dSJames Kremer * Format of log str is as follows
365e4f5a11dSJames Kremer * "%8x %8x %8x %8x %8x %8x %8x %8x",
366e4f5a11dSJames Kremer * log_entry.log_word0, log_entry.ts_u, log_entry.ts_l,
367e4f5a11dSJames Kremer * log_entry.seq_num, log_entry.log_code, log_entry.log_word2,
368e4f5a11dSJames Kremer * log_entry.log_word3, log_entry.log_word4
369e4f5a11dSJames Kremer * following example has extra spaces removed to fit in 80 char
370e4f5a11dSJames Kremer * 40004 0 42d5f5fe 185b 630002 fd0800 50800207 e482813
371e4f5a11dSJames Kremer */
372e4f5a11dSJames Kremer
373e4f5a11dSJames Kremer (void) strncpy(save_buffer,
374e4f5a11dSJames Kremer (const char *)log_str_ptr,
375e4f5a11dSJames Kremer SES_LOG_VALID_LOG_SIZE);
376e4f5a11dSJames Kremer
3775cf8276bSTodd McKenney (void) strncpy(log_code,
3785cf8276bSTodd McKenney (const char *)log_str_ptr+SES_LOG_CODE_START,
3795cf8276bSTodd McKenney SES_LOG_SPECIFIC_ENTRY_SIZE);
380e4f5a11dSJames Kremer
381e4f5a11dSJames Kremer (void) strncpy(log_level,
382e4f5a11dSJames Kremer (const char *) log_str_ptr +
383e4f5a11dSJames Kremer SES_LOG_LEVEL_START, 1);
384e4f5a11dSJames Kremer
385e4f5a11dSJames Kremer
386e4f5a11dSJames Kremer /* Add this entry to the nvlist log data */
3875cf8276bSTodd McKenney if (nvlist_alloc(&entry, NV_UNIQUE_NAME, 0) != 0) {
3885cf8276bSTodd McKenney /* Couldn't alloc space, return error */
389e4f5a11dSJames Kremer return (SES_LOG_FAILED_NV_UNIQUE);
390e4f5a11dSJames Kremer }
391e4f5a11dSJames Kremer
392e4f5a11dSJames Kremer
3935cf8276bSTodd McKenney if (nvlist_add_string(entry, ENTRY_LOG, save_buffer) != 0) {
3945cf8276bSTodd McKenney /* Error adding string, return error */
395e4f5a11dSJames Kremer nvlist_free(entry);
396e4f5a11dSJames Kremer return (SES_LOG_FAILED_NV_LOG);
397e4f5a11dSJames Kremer }
398e4f5a11dSJames Kremer
3995cf8276bSTodd McKenney if (nvlist_add_string(entry, ENTRY_CODE, log_code) != 0) {
4005cf8276bSTodd McKenney /* Error adding string, return error */
401e4f5a11dSJames Kremer nvlist_free(entry);
402e4f5a11dSJames Kremer return (SES_LOG_FAILED_NV_CODE);
403e4f5a11dSJames Kremer }
4045cf8276bSTodd McKenney if (nvlist_add_string(entry, ENTRY_SEVERITY, log_level) != 0) {
4055cf8276bSTodd McKenney /* Error adding srtring, return error */
406e4f5a11dSJames Kremer nvlist_free(entry);
407e4f5a11dSJames Kremer return (SES_LOG_FAILED_NV_SEV);
408e4f5a11dSJames Kremer }
409e4f5a11dSJames Kremer
4105cf8276bSTodd McKenney param_code = SCSI_READ16(&log_param_ptr[0]);
411e4f5a11dSJames Kremer
4125cf8276bSTodd McKenney (void) snprintf(entry_num, sizeof (entry_num),
4135cf8276bSTodd McKenney "%s%d", ENTRY_PREFIX, param_code);
4145cf8276bSTodd McKenney
4155cf8276bSTodd McKenney if (nvlist_add_nvlist(data->log_data, entry_num, entry) != 0) {
4165cf8276bSTodd McKenney /* Error adding nvlist, return error */
417e4f5a11dSJames Kremer nvlist_free(entry);
418e4f5a11dSJames Kremer return (SES_LOG_FAILED_NV_ENTRY);
419e4f5a11dSJames Kremer }
420e4f5a11dSJames Kremer nvlist_free(entry);
421e4f5a11dSJames Kremer
422e4f5a11dSJames Kremer entry_added = 1;
4235cf8276bSTodd McKenney (data->number_log_entries)++;
424e4f5a11dSJames Kremer
4255cf8276bSTodd McKenney log_param_ptr += param_len;
426e4f5a11dSJames Kremer
427e4f5a11dSJames Kremer }
428e4f5a11dSJames Kremer if (entry_added) {
429e4f5a11dSJames Kremer /* Update the last log entry string with last one read */
4305cf8276bSTodd McKenney (void) strncpy(data->last_log_entry, save_buffer, MAXNAMELEN);
431e4f5a11dSJames Kremer }
432e4f5a11dSJames Kremer return (0);
433e4f5a11dSJames Kremer }
434e4f5a11dSJames Kremer
435e4f5a11dSJames Kremer
436e4f5a11dSJames Kremer
437e4f5a11dSJames Kremer /* Setup struct to send command to device */
438e4f5a11dSJames Kremer static void
set_scsi_pt_data_out(struct uscsi_cmd * uscsi,const unsigned char * dxferp,int dxfer_len)439e4f5a11dSJames Kremer set_scsi_pt_data_out(struct uscsi_cmd *uscsi, const unsigned char *dxferp,
440e4f5a11dSJames Kremer int dxfer_len)
441e4f5a11dSJames Kremer {
442e4f5a11dSJames Kremer if (dxfer_len > 0) {
443e4f5a11dSJames Kremer uscsi->uscsi_bufaddr = (char *)dxferp;
444e4f5a11dSJames Kremer uscsi->uscsi_buflen = dxfer_len;
445e4f5a11dSJames Kremer uscsi->uscsi_flags = USCSI_WRITE | USCSI_ISOLATE |
446e4f5a11dSJames Kremer USCSI_RQENABLE;
447e4f5a11dSJames Kremer }
448e4f5a11dSJames Kremer }
449e4f5a11dSJames Kremer
450e4f5a11dSJames Kremer /*
451e4f5a11dSJames Kremer * Invokes a SCSI MODE SENSE(10) command.
452e4f5a11dSJames Kremer * Return:
453e4f5a11dSJames Kremer * 0 for success
454e4f5a11dSJames Kremer * SG_LIB_CAT_INVALID_OP -> invalid opcode
455e4f5a11dSJames Kremer * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb
456e4f5a11dSJames Kremer * SG_LIB_CAT_NOT_READY -> device not ready
457e4f5a11dSJames Kremer * -1 -> other failure
458e4f5a11dSJames Kremer */
459e4f5a11dSJames Kremer
460e4f5a11dSJames Kremer static int
sg_ll_mode_sense10(int sg_fd,void * resp,int mx_resp_len)461e4f5a11dSJames Kremer sg_ll_mode_sense10(int sg_fd, void * resp, int mx_resp_len)
462e4f5a11dSJames Kremer {
463e4f5a11dSJames Kremer int res, ret;
464e4f5a11dSJames Kremer unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
465e4f5a11dSJames Kremer {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
466e4f5a11dSJames Kremer unsigned char sense_b[SENSE_BUFF_LEN];
467e4f5a11dSJames Kremer struct uscsi_cmd uscsi;
468e4f5a11dSJames Kremer
469e4f5a11dSJames Kremer modesCmdBlk[1] = 0;
470e4f5a11dSJames Kremer modesCmdBlk[2] = 0; /* page code 0 vendor specific */
471e4f5a11dSJames Kremer modesCmdBlk[3] = 0;
472e4f5a11dSJames Kremer modesCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff);
473e4f5a11dSJames Kremer modesCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff);
474e4f5a11dSJames Kremer
475e4f5a11dSJames Kremer construct_scsi_pt_obj(&uscsi);
476e4f5a11dSJames Kremer set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
477e4f5a11dSJames Kremer set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
478e4f5a11dSJames Kremer set_scsi_pt_data_in(&uscsi, (unsigned char *) resp, mx_resp_len);
479e4f5a11dSJames Kremer res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
480e4f5a11dSJames Kremer if (res) {
481e4f5a11dSJames Kremer ret = res;
482e4f5a11dSJames Kremer } else {
483e4f5a11dSJames Kremer ret = uscsi.uscsi_status;
484e4f5a11dSJames Kremer }
485e4f5a11dSJames Kremer return (ret);
486e4f5a11dSJames Kremer }
487e4f5a11dSJames Kremer
488e4f5a11dSJames Kremer /*
489e4f5a11dSJames Kremer * Invokes a SCSI MODE SELECT(10) command.
490e4f5a11dSJames Kremer * Return:
491e4f5a11dSJames Kremer * 0 for success.
492e4f5a11dSJames Kremer * SG_LIB_CAT_INVALID_OP for invalid opcode
493e4f5a11dSJames Kremer * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
494e4f5a11dSJames Kremer * SG_LIB_CAT_NOT_READY -> device not ready,
495e4f5a11dSJames Kremer * -1 -> other failure
496e4f5a11dSJames Kremer */
497e4f5a11dSJames Kremer static int
sg_ll_mode_select10(int sg_fd,void * paramp,int param_len)498e4f5a11dSJames Kremer sg_ll_mode_select10(int sg_fd, void * paramp, int param_len)
499e4f5a11dSJames Kremer {
500e4f5a11dSJames Kremer int res, ret;
501e4f5a11dSJames Kremer unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] =
502e4f5a11dSJames Kremer {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
503e4f5a11dSJames Kremer unsigned char sense_b[SENSE_BUFF_LEN];
504e4f5a11dSJames Kremer struct uscsi_cmd uscsi;
505e4f5a11dSJames Kremer
506e4f5a11dSJames Kremer
507e4f5a11dSJames Kremer modesCmdBlk[1] = 0;
508e4f5a11dSJames Kremer /*
509e4f5a11dSJames Kremer * modesCmdBlk 2 equal 0 PC 0 return current page code 0 return
510e4f5a11dSJames Kremer * vendor specific
511e4f5a11dSJames Kremer */
512e4f5a11dSJames Kremer
513e4f5a11dSJames Kremer modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
514e4f5a11dSJames Kremer modesCmdBlk[8] = (unsigned char)(param_len & 0xff);
515e4f5a11dSJames Kremer
516e4f5a11dSJames Kremer construct_scsi_pt_obj(&uscsi);
517e4f5a11dSJames Kremer
518e4f5a11dSJames Kremer set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
519e4f5a11dSJames Kremer set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
520e4f5a11dSJames Kremer set_scsi_pt_data_out(&uscsi, (unsigned char *) paramp, param_len);
521e4f5a11dSJames Kremer res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
522e4f5a11dSJames Kremer if (res) {
523e4f5a11dSJames Kremer ret = res;
524e4f5a11dSJames Kremer } else {
525e4f5a11dSJames Kremer ret = uscsi.uscsi_status;
526e4f5a11dSJames Kremer }
527e4f5a11dSJames Kremer return (ret);
528e4f5a11dSJames Kremer }
529e4f5a11dSJames Kremer
530e4f5a11dSJames Kremer
531e4f5a11dSJames Kremer
532e4f5a11dSJames Kremer /*
533e4f5a11dSJames Kremer * MODE SENSE 10 commands yield a response that has block descriptors followed
534e4f5a11dSJames Kremer * by mode pages. In most cases users are interested in the first mode page.
535e4f5a11dSJames Kremer * This function returns the(byte) offset of the start of the first mode page.
536e4f5a11dSJames Kremer * Returns >= 0 is successful or -1 if failure. If there is a failure
537e4f5a11dSJames Kremer * a message is written to err_buff.
538e4f5a11dSJames Kremer */
539e4f5a11dSJames Kremer
540e4f5a11dSJames Kremer /*
541e4f5a11dSJames Kremer * return data looks like:
542e4f5a11dSJames Kremer * Table 92 - Mode parameter header(10)
543e4f5a11dSJames Kremer * Bit
544e4f5a11dSJames Kremer * Byte
545e4f5a11dSJames Kremer * 7 6 5 4 3 2 1 0
546e4f5a11dSJames Kremer * ----------------------------------------------------------
547e4f5a11dSJames Kremer * 0 MSB Data length
548e4f5a11dSJames Kremer * 1 LSB Data length
549e4f5a11dSJames Kremer * ----------------------------------------------------------
550e4f5a11dSJames Kremer * 2 Medium type
551e4f5a11dSJames Kremer * ----------------------------------------------------------
552e4f5a11dSJames Kremer * 3 Device-specific parameter
553e4f5a11dSJames Kremer * ----------------------------------------------------------
554e4f5a11dSJames Kremer * 4 Reserved
555e4f5a11dSJames Kremer * ----------------------------------------------------------
556e4f5a11dSJames Kremer * 5 Reserved
557e4f5a11dSJames Kremer * ----------------------------------------------------------
558e4f5a11dSJames Kremer * 6 MSB block descriptor length
559e4f5a11dSJames Kremer * 7 LSB block descriptor length
560e4f5a11dSJames Kremer * ----------------------------------------------------------
561e4f5a11dSJames Kremer * block desciptors....
562e4f5a11dSJames Kremer * -----------------------
563e4f5a11dSJames Kremer * mode sense page:
564e4f5a11dSJames Kremer * 0 : ps Reserved : page Code
565e4f5a11dSJames Kremer * 1 : Page Length(n-1)
566e4f5a11dSJames Kremer * 2-N Mode parameters
567e4f5a11dSJames Kremer */
568e4f5a11dSJames Kremer static int
sg_mode_page_offset(const unsigned char * resp,int resp_len)5695cf8276bSTodd McKenney sg_mode_page_offset(const unsigned char *resp, int resp_len)
570e4f5a11dSJames Kremer {
571e4f5a11dSJames Kremer int bd_len;
572e4f5a11dSJames Kremer int calc_len;
573e4f5a11dSJames Kremer int offset;
574e4f5a11dSJames Kremer
575e4f5a11dSJames Kremer if ((NULL == resp) || (resp_len < 8)) {
576e4f5a11dSJames Kremer /* Too short of a response buffer */
577e4f5a11dSJames Kremer return (-1);
578e4f5a11dSJames Kremer }
579e4f5a11dSJames Kremer
580e4f5a11dSJames Kremer calc_len = (resp[0] << 8) + resp[1] + 2;
581e4f5a11dSJames Kremer bd_len = (resp[6] << 8) + resp[7];
582e4f5a11dSJames Kremer
583e4f5a11dSJames Kremer /* LongLBA doesn't change this calculation */
584e4f5a11dSJames Kremer offset = bd_len + MODE10_RESP_HDR_LEN;
585e4f5a11dSJames Kremer
586e4f5a11dSJames Kremer if ((offset + 2) > resp_len) {
5875cf8276bSTodd McKenney /* Given response length to small */
588e4f5a11dSJames Kremer offset = -1;
589e4f5a11dSJames Kremer } else if ((offset + 2) > calc_len) {
5905cf8276bSTodd McKenney /* Calculated response length too small */
591e4f5a11dSJames Kremer offset = -1;
592e4f5a11dSJames Kremer }
593e4f5a11dSJames Kremer return (offset);
594e4f5a11dSJames Kremer }
595e4f5a11dSJames Kremer
596e4f5a11dSJames Kremer /*
597e4f5a11dSJames Kremer * Clear logs
598e4f5a11dSJames Kremer */
599e4f5a11dSJames Kremer static int
clear_log(int sg_fd,ses_log_call_t * data)6005cf8276bSTodd McKenney clear_log(int sg_fd, ses_log_call_t *data)
601e4f5a11dSJames Kremer {
602e4f5a11dSJames Kremer
603e4f5a11dSJames Kremer int res, alloc_len, off;
604e4f5a11dSJames Kremer int md_len;
605e4f5a11dSJames Kremer int read_in_len = 0;
6065cf8276bSTodd McKenney unsigned char ref_md[MAX_ALLOC_LEN];
607e4f5a11dSJames Kremer struct log_clear_control_struct clear_data;
608e4f5a11dSJames Kremer long myhostid;
609e4f5a11dSJames Kremer int error = 0;
6105cf8276bSTodd McKenney long poll_time;
6115cf8276bSTodd McKenney char seq_num_str[10];
6125cf8276bSTodd McKenney unsigned long seq_num = 0;
613e4f5a11dSJames Kremer
614e4f5a11dSJames Kremer (void) memset(&clear_data, 0, sizeof (clear_data));
615e4f5a11dSJames Kremer
616e4f5a11dSJames Kremer clear_data.pageControls = 0x40;
617e4f5a11dSJames Kremer clear_data.subpage_code = 0;
618e4f5a11dSJames Kremer clear_data.page_lengthLower = 0x16;
619e4f5a11dSJames Kremer
620e4f5a11dSJames Kremer myhostid = gethostid();
621e4f5a11dSJames Kremer /* 0 -> 11 are memset to 0 */
622e4f5a11dSJames Kremer clear_data.host_id[12] = (myhostid & 0xff000000) >> 24;
623e4f5a11dSJames Kremer clear_data.host_id[13] = (myhostid & 0xff0000) >> 16;
624e4f5a11dSJames Kremer clear_data.host_id[14] = (myhostid & 0xff00) >> 8;
625e4f5a11dSJames Kremer clear_data.host_id[15] = myhostid & 0xff;
626e4f5a11dSJames Kremer
6275cf8276bSTodd McKenney /*
6285cf8276bSTodd McKenney * convert nanosecond time to seconds
6295cf8276bSTodd McKenney */
6305cf8276bSTodd McKenney poll_time = data->poll_time / 1000000000;
6315cf8276bSTodd McKenney /* Add 5 minutes to poll time to allow for data retrieval time */
632e4f5a11dSJames Kremer poll_time = poll_time + 300;
633e4f5a11dSJames Kremer clear_data.timeout[0] = (poll_time & 0xff00) >> 8;
634e4f5a11dSJames Kremer clear_data.timeout[1] = poll_time & 0xff;
635e4f5a11dSJames Kremer
6365cf8276bSTodd McKenney /*
6375cf8276bSTodd McKenney * retrieve the last read sequence number from the last
6385cf8276bSTodd McKenney * log entry read.
6395cf8276bSTodd McKenney */
640*c56822beSToomas Soome if (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE) {
6415cf8276bSTodd McKenney /*
6425cf8276bSTodd McKenney * We have a valid log entry from a previous read log
6435cf8276bSTodd McKenney * operation.
6445cf8276bSTodd McKenney */
6455cf8276bSTodd McKenney (void) strncpy(seq_num_str,
6465cf8276bSTodd McKenney (const char *) data->last_log_entry +
6475cf8276bSTodd McKenney SES_LOG_SEQ_NUM_START, 8);
6485cf8276bSTodd McKenney seq_num = strtoul(seq_num_str, 0, 16);
6495cf8276bSTodd McKenney }
650e4f5a11dSJames Kremer clear_data.seq_clear[0] = (seq_num & 0xff000000) >> 24;
651e4f5a11dSJames Kremer clear_data.seq_clear[1] = (seq_num & 0xff0000) >> 16;
652e4f5a11dSJames Kremer clear_data.seq_clear[2] = (seq_num & 0xff00) >> 8;
653e4f5a11dSJames Kremer clear_data.seq_clear[3] = (seq_num & 0xff);
654e4f5a11dSJames Kremer
655e4f5a11dSJames Kremer read_in_len = sizeof (clear_data);
656e4f5a11dSJames Kremer
657e4f5a11dSJames Kremer
658e4f5a11dSJames Kremer /* do MODE SENSE to fetch current values */
6595cf8276bSTodd McKenney (void) memset(ref_md, 0, MAX_ALLOC_LEN);
6605cf8276bSTodd McKenney alloc_len = MAX_ALLOC_LEN;
661e4f5a11dSJames Kremer
662e4f5a11dSJames Kremer
663e4f5a11dSJames Kremer res = sg_ll_mode_sense10(sg_fd, ref_md, alloc_len);
664e4f5a11dSJames Kremer if (0 != res) {
665e4f5a11dSJames Kremer /* Error during mode sense */
666e4f5a11dSJames Kremer error = SES_LOG_FAILED_MODE_SENSE;
667e4f5a11dSJames Kremer return (error);
668e4f5a11dSJames Kremer }
669e4f5a11dSJames Kremer
670e4f5a11dSJames Kremer /* Setup mode Select to clear logs */
6715cf8276bSTodd McKenney off = sg_mode_page_offset(ref_md, alloc_len);
672e4f5a11dSJames Kremer if (off < 0) {
673e4f5a11dSJames Kremer /* Mode page offset error */
674e4f5a11dSJames Kremer error = SES_LOG_FAILED_MODE_SENSE_OFFSET;
675e4f5a11dSJames Kremer return (error);
676e4f5a11dSJames Kremer }
677e4f5a11dSJames Kremer md_len = (ref_md[0] << 8) + ref_md[1] + 2;
678e4f5a11dSJames Kremer
679e4f5a11dSJames Kremer ref_md[0] = 0;
680e4f5a11dSJames Kremer ref_md[1] = 0;
681e4f5a11dSJames Kremer
682e4f5a11dSJames Kremer if (md_len > alloc_len) {
683e4f5a11dSJames Kremer /* Data length to large */
684e4f5a11dSJames Kremer error = SES_LOG_FAILED_BAD_DATA_LEN;
685e4f5a11dSJames Kremer return (error);
686e4f5a11dSJames Kremer }
687e4f5a11dSJames Kremer
688e4f5a11dSJames Kremer if ((md_len - off) != read_in_len) {
689e4f5a11dSJames Kremer /* Content length not correct */
690e4f5a11dSJames Kremer error = SES_LOG_FAILED_BAD_CONTENT_LEN;
691e4f5a11dSJames Kremer return (error);
692e4f5a11dSJames Kremer }
693e4f5a11dSJames Kremer
694e4f5a11dSJames Kremer if ((clear_data.pageControls & 0x40) != (ref_md[off] & 0x40)) {
695e4f5a11dSJames Kremer /* reference model doesn't have use subpage format bit set */
696e4f5a11dSJames Kremer /* Even though it should have */
697e4f5a11dSJames Kremer /* don't send the command */
6985cf8276bSTodd McKenney error = SES_LOG_FAILED_FORMAT_PAGE_ERR;
699e4f5a11dSJames Kremer return (error);
700e4f5a11dSJames Kremer }
701e4f5a11dSJames Kremer
702e4f5a11dSJames Kremer (void) memcpy(ref_md + off, (const void *) &clear_data,
703e4f5a11dSJames Kremer sizeof (clear_data));
704e4f5a11dSJames Kremer
705e4f5a11dSJames Kremer res = sg_ll_mode_select10(sg_fd, ref_md, md_len);
706e4f5a11dSJames Kremer if (res != 0) {
707e4f5a11dSJames Kremer error = SES_LOG_FAILED_MODE_SELECT;
708e4f5a11dSJames Kremer return (error);
709e4f5a11dSJames Kremer }
710e4f5a11dSJames Kremer
711e4f5a11dSJames Kremer return (error);
712e4f5a11dSJames Kremer }
713e4f5a11dSJames Kremer /*
714e4f5a11dSJames Kremer * Gather data from given device.
715e4f5a11dSJames Kremer */
716e4f5a11dSJames Kremer static int
gather_data(char * device_name,ses_log_call_t * data)7175cf8276bSTodd McKenney gather_data(char *device_name, ses_log_call_t *data)
718e4f5a11dSJames Kremer {
719e4f5a11dSJames Kremer int sg_fd;
7205cf8276bSTodd McKenney int resp_len, res;
7215cf8276bSTodd McKenney unsigned char rsp_buff[MAX_ALLOC_LEN];
722e4f5a11dSJames Kremer int error;
723e4f5a11dSJames Kremer
724e4f5a11dSJames Kremer /* Open device */
725e4f5a11dSJames Kremer if ((sg_fd = open_device(device_name)) < 0) {
726e4f5a11dSJames Kremer /* Failed to open device */
727e4f5a11dSJames Kremer return (SES_LOG_FAILED_TO_OPEN_DEVICE);
728e4f5a11dSJames Kremer }
729e4f5a11dSJames Kremer
730e4f5a11dSJames Kremer /* Read the logs */
731e4f5a11dSJames Kremer (void) memset(rsp_buff, 0, sizeof (rsp_buff));
732e4f5a11dSJames Kremer resp_len = 0x8000; /* Maximum size available to read */
733e4f5a11dSJames Kremer res = read_log(sg_fd, rsp_buff, resp_len);
734e4f5a11dSJames Kremer
7355cf8276bSTodd McKenney if (res != 0) {
736e4f5a11dSJames Kremer /* Some sort of Error during read of logs */
7375cf8276bSTodd McKenney (void) close(sg_fd);
738e4f5a11dSJames Kremer return (SES_LOG_FAILED_TO_READ_DEVICE);
739e4f5a11dSJames Kremer }
740e4f5a11dSJames Kremer
741e4f5a11dSJames Kremer /* Save the logs */
7425cf8276bSTodd McKenney error = save_logs(rsp_buff, data);
743e4f5a11dSJames Kremer if (error != 0) {
7445cf8276bSTodd McKenney (void) close(sg_fd);
745e4f5a11dSJames Kremer return (error);
746e4f5a11dSJames Kremer }
7475cf8276bSTodd McKenney /* Clear the logs */
7485cf8276bSTodd McKenney error = clear_log(sg_fd, data);
749e4f5a11dSJames Kremer
750e4f5a11dSJames Kremer (void) close(sg_fd);
751e4f5a11dSJames Kremer
752e4f5a11dSJames Kremer return (error);
753e4f5a11dSJames Kremer }
754e4f5a11dSJames Kremer
755e4f5a11dSJames Kremer /*
756e4f5a11dSJames Kremer * Access the SES target identified by the indicated path. Read the logs
757e4f5a11dSJames Kremer * and return them in a nvlist.
758e4f5a11dSJames Kremer */
759e4f5a11dSJames Kremer int
access_ses_log(ses_log_call_t * data)7605cf8276bSTodd McKenney access_ses_log(ses_log_call_t *data)
761e4f5a11dSJames Kremer {
762e4f5a11dSJames Kremer char real_path[MAXPATHLEN];
763e4f5a11dSJames Kremer struct stat buffer;
764e4f5a11dSJames Kremer int error;
765e4f5a11dSJames Kremer
7665cf8276bSTodd McKenney /* Initialize return data */
7675cf8276bSTodd McKenney data->log_data = NULL;
7685cf8276bSTodd McKenney data->number_log_entries = 0;
7695cf8276bSTodd McKenney
770*c56822beSToomas Soome if (*data->target_path == '\0') {
771*c56822beSToomas Soome /* empty target path, return error */
772e4f5a11dSJames Kremer return (SES_LOG_FAILED_NULL_TARGET_PATH);
773e4f5a11dSJames Kremer }
774e4f5a11dSJames Kremer
775e4f5a11dSJames Kremer /* Try to find a valid path */
776e4f5a11dSJames Kremer (void) snprintf(real_path, sizeof (real_path), "/devices%s:ses",
777e4f5a11dSJames Kremer data->target_path);
778e4f5a11dSJames Kremer
779e4f5a11dSJames Kremer if (stat(real_path, &buffer) != 0) {
780e4f5a11dSJames Kremer
781e4f5a11dSJames Kremer (void) snprintf(real_path, sizeof (real_path), "/devices%s:0",
782e4f5a11dSJames Kremer data->target_path);
783e4f5a11dSJames Kremer if (stat(real_path, &buffer) != 0) {
784e4f5a11dSJames Kremer /* Couldn't find a path that exists */
785e4f5a11dSJames Kremer return (SES_LOG_FAILED_BAD_TARGET_PATH);
786e4f5a11dSJames Kremer }
787e4f5a11dSJames Kremer }
788e4f5a11dSJames Kremer
7895cf8276bSTodd McKenney error = gather_data(real_path, data);
790e4f5a11dSJames Kremer
791e4f5a11dSJames Kremer /* Update the size of log entries being returned */
792e4f5a11dSJames Kremer data->size_of_log_entries =
793e4f5a11dSJames Kremer data->number_log_entries * SES_LOG_VALID_LOG_SIZE;
794e4f5a11dSJames Kremer
795e4f5a11dSJames Kremer return (error);
796e4f5a11dSJames Kremer }
797