112767SJames.Kremer@Sun.COM /*
212767SJames.Kremer@Sun.COM * CDDL HEADER START
312767SJames.Kremer@Sun.COM *
412767SJames.Kremer@Sun.COM * The contents of this file are subject to the terms of the
512767SJames.Kremer@Sun.COM * Common Development and Distribution License (the "License").
612767SJames.Kremer@Sun.COM * You may not use this file except in compliance with the License.
712767SJames.Kremer@Sun.COM *
812767SJames.Kremer@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912767SJames.Kremer@Sun.COM * or http://www.opensolaris.org/os/licensing.
1012767SJames.Kremer@Sun.COM * See the License for the specific language governing permissions
1112767SJames.Kremer@Sun.COM * and limitations under the License.
1212767SJames.Kremer@Sun.COM *
1312767SJames.Kremer@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1412767SJames.Kremer@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512767SJames.Kremer@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1612767SJames.Kremer@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1712767SJames.Kremer@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1812767SJames.Kremer@Sun.COM *
1912767SJames.Kremer@Sun.COM * CDDL HEADER END
2012767SJames.Kremer@Sun.COM */
2112767SJames.Kremer@Sun.COM /*
2212767SJames.Kremer@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2312767SJames.Kremer@Sun.COM */
2412767SJames.Kremer@Sun.COM
2512767SJames.Kremer@Sun.COM /*
2612767SJames.Kremer@Sun.COM * SES Log reader library
2712767SJames.Kremer@Sun.COM *
2812767SJames.Kremer@Sun.COM * This library is responsible for accessing the SES log at the target address,
2912767SJames.Kremer@Sun.COM * formatting and returning any log entries found.
3012767SJames.Kremer@Sun.COM *
3112767SJames.Kremer@Sun.COM * The data will be returned in an nvlist_t structure allocated here.
3212767SJames.Kremer@Sun.COM */
3312767SJames.Kremer@Sun.COM
3412767SJames.Kremer@Sun.COM #include <assert.h>
3512767SJames.Kremer@Sun.COM #include <errno.h>
3612767SJames.Kremer@Sun.COM #include <fcntl.h>
3712767SJames.Kremer@Sun.COM #include <sys/param.h>
3812767SJames.Kremer@Sun.COM #include <libseslog.h>
3912767SJames.Kremer@Sun.COM #include <stdlib.h>
4012767SJames.Kremer@Sun.COM #include <string.h>
4112767SJames.Kremer@Sun.COM #include <sys/stat.h>
4212767SJames.Kremer@Sun.COM #include <unistd.h>
4312767SJames.Kremer@Sun.COM #include <dirent.h>
4412767SJames.Kremer@Sun.COM #include <sys/scsi/generic/commands.h>
4512767SJames.Kremer@Sun.COM #include <sys/scsi/generic/status.h>
46*12843Stodd.mckenney@oracle.com #include <sys/scsi/impl/commands.h>
4712767SJames.Kremer@Sun.COM
4812767SJames.Kremer@Sun.COM /*
4912767SJames.Kremer@Sun.COM * open the device with given device name
5012767SJames.Kremer@Sun.COM */
5112767SJames.Kremer@Sun.COM static int
open_device(const char * device_name)5212767SJames.Kremer@Sun.COM open_device(const char *device_name)
5312767SJames.Kremer@Sun.COM {
5412767SJames.Kremer@Sun.COM int oflags = O_NONBLOCK | O_RDWR;
5512767SJames.Kremer@Sun.COM int fd;
5612767SJames.Kremer@Sun.COM
5712767SJames.Kremer@Sun.COM fd = open(device_name, oflags);
5812767SJames.Kremer@Sun.COM if (fd < 0)
5912767SJames.Kremer@Sun.COM fd = -errno;
6012767SJames.Kremer@Sun.COM return (fd);
6112767SJames.Kremer@Sun.COM }
6212767SJames.Kremer@Sun.COM
6312767SJames.Kremer@Sun.COM /*
6412767SJames.Kremer@Sun.COM * Initialize scsi struct
6512767SJames.Kremer@Sun.COM */
6612767SJames.Kremer@Sun.COM static void
construct_scsi_pt_obj(struct uscsi_cmd * uscsi)6712767SJames.Kremer@Sun.COM construct_scsi_pt_obj(struct uscsi_cmd *uscsi)
6812767SJames.Kremer@Sun.COM {
6912767SJames.Kremer@Sun.COM (void) memset(uscsi, 0, sizeof (struct uscsi_cmd));
7012767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = DEF_PT_TIMEOUT;
7112767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE;
7212767SJames.Kremer@Sun.COM }
7312767SJames.Kremer@Sun.COM
7412767SJames.Kremer@Sun.COM /*
7512767SJames.Kremer@Sun.COM * set control cdb of scsi structure
7612767SJames.Kremer@Sun.COM */
7712767SJames.Kremer@Sun.COM static void
set_scsi_pt_cdb(struct uscsi_cmd * uscsi,const unsigned char * cdb,int cdb_len)7812767SJames.Kremer@Sun.COM set_scsi_pt_cdb(struct uscsi_cmd *uscsi, const unsigned char *cdb,
7912767SJames.Kremer@Sun.COM int cdb_len)
8012767SJames.Kremer@Sun.COM {
8112767SJames.Kremer@Sun.COM uscsi->uscsi_cdb = (char *)cdb;
8212767SJames.Kremer@Sun.COM uscsi->uscsi_cdblen = cdb_len;
8312767SJames.Kremer@Sun.COM }
8412767SJames.Kremer@Sun.COM
8512767SJames.Kremer@Sun.COM /*
8612767SJames.Kremer@Sun.COM * initialize sense data
8712767SJames.Kremer@Sun.COM */
8812767SJames.Kremer@Sun.COM static void
set_scsi_pt_sense(struct uscsi_cmd * uscsi,unsigned char * sense,int max_sense_len)8912767SJames.Kremer@Sun.COM set_scsi_pt_sense(struct uscsi_cmd *uscsi, unsigned char *sense,
9012767SJames.Kremer@Sun.COM int max_sense_len)
9112767SJames.Kremer@Sun.COM {
9212767SJames.Kremer@Sun.COM (void) memset(sense, 0, max_sense_len);
9312767SJames.Kremer@Sun.COM uscsi->uscsi_rqbuf = (char *)sense;
9412767SJames.Kremer@Sun.COM uscsi->uscsi_rqlen = max_sense_len;
9512767SJames.Kremer@Sun.COM }
9612767SJames.Kremer@Sun.COM
9712767SJames.Kremer@Sun.COM /*
9812767SJames.Kremer@Sun.COM * Initialize data going to device
9912767SJames.Kremer@Sun.COM */
10012767SJames.Kremer@Sun.COM static void
set_scsi_pt_data_in(struct uscsi_cmd * uscsi,unsigned char * dxferp,int dxfer_len)10112767SJames.Kremer@Sun.COM set_scsi_pt_data_in(struct uscsi_cmd *uscsi, unsigned char *dxferp,
10212767SJames.Kremer@Sun.COM int dxfer_len)
10312767SJames.Kremer@Sun.COM {
10412767SJames.Kremer@Sun.COM if (dxfer_len > 0) {
10512767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp;
10612767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len;
10712767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_READ | USCSI_ISOLATE |
10812767SJames.Kremer@Sun.COM USCSI_RQENABLE;
10912767SJames.Kremer@Sun.COM }
11012767SJames.Kremer@Sun.COM }
11112767SJames.Kremer@Sun.COM
11212767SJames.Kremer@Sun.COM /*
11312767SJames.Kremer@Sun.COM * Executes SCSI command(or at least forwards it to lower layers).
11412767SJames.Kremer@Sun.COM */
11512767SJames.Kremer@Sun.COM static int
do_scsi_pt(struct uscsi_cmd * uscsi,int fd,int time_secs)11612767SJames.Kremer@Sun.COM do_scsi_pt(struct uscsi_cmd *uscsi, int fd, int time_secs)
11712767SJames.Kremer@Sun.COM {
11812767SJames.Kremer@Sun.COM if (time_secs > 0)
11912767SJames.Kremer@Sun.COM uscsi->uscsi_timeout = time_secs;
12012767SJames.Kremer@Sun.COM
12112767SJames.Kremer@Sun.COM if (ioctl(fd, USCSICMD, uscsi)) {
12212767SJames.Kremer@Sun.COM /* Took an error */
12312767SJames.Kremer@Sun.COM return (errno);
12412767SJames.Kremer@Sun.COM }
12512767SJames.Kremer@Sun.COM return (0);
12612767SJames.Kremer@Sun.COM }
12712767SJames.Kremer@Sun.COM
12812767SJames.Kremer@Sun.COM
12912767SJames.Kremer@Sun.COM /*
13012767SJames.Kremer@Sun.COM * Read log from device
13112767SJames.Kremer@Sun.COM * Invokes a SCSI LOG SENSE command.
13212767SJames.Kremer@Sun.COM * Return:
13312767SJames.Kremer@Sun.COM * 0 -> success
13412767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> Log Sense not supported,
13512767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
13612767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready,
13712767SJames.Kremer@Sun.COM * -1 -> other failure
13812767SJames.Kremer@Sun.COM */
13912767SJames.Kremer@Sun.COM
14012767SJames.Kremer@Sun.COM static int
read_log(int sg_fd,unsigned char * resp,int mx_resp_len)14112767SJames.Kremer@Sun.COM read_log(int sg_fd, unsigned char *resp, int mx_resp_len)
14212767SJames.Kremer@Sun.COM {
14312767SJames.Kremer@Sun.COM int res, ret;
14412767SJames.Kremer@Sun.COM unsigned char logsCmdBlk[CDB_GROUP1] =
14512767SJames.Kremer@Sun.COM {SCMD_LOG_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
14612767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN];
14712767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi;
14812767SJames.Kremer@Sun.COM
14912767SJames.Kremer@Sun.COM if (mx_resp_len > 0xffff) {
15012767SJames.Kremer@Sun.COM return (-1);
15112767SJames.Kremer@Sun.COM }
15212767SJames.Kremer@Sun.COM logsCmdBlk[1] = 0;
15312767SJames.Kremer@Sun.COM /* pc = 1, pg_code = 0x7 (logs page) */
15412767SJames.Kremer@Sun.COM /* (((pc << 6) & 0xc0) | (pg_code & 0x3f)) = 0x47; */
15512767SJames.Kremer@Sun.COM logsCmdBlk[2] = 0x47;
15612767SJames.Kremer@Sun.COM /* pc = 1 current values */
15712767SJames.Kremer@Sun.COM logsCmdBlk[3] = 0; /* No subpage code */
15812767SJames.Kremer@Sun.COM logsCmdBlk[5] = 0; /* Want all logs starting from 0 */
15912767SJames.Kremer@Sun.COM logsCmdBlk[6] = 0;
16012767SJames.Kremer@Sun.COM logsCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff);
16112767SJames.Kremer@Sun.COM logsCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff);
16212767SJames.Kremer@Sun.COM
16312767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi);
16412767SJames.Kremer@Sun.COM
16512767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, logsCmdBlk, sizeof (logsCmdBlk));
16612767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
16712767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, resp, mx_resp_len);
16812767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
16912767SJames.Kremer@Sun.COM if (res) {
17012767SJames.Kremer@Sun.COM ret = res;
17112767SJames.Kremer@Sun.COM } else {
17212767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status;
17312767SJames.Kremer@Sun.COM }
17412767SJames.Kremer@Sun.COM return (ret);
17512767SJames.Kremer@Sun.COM }
17612767SJames.Kremer@Sun.COM
17712767SJames.Kremer@Sun.COM /*
17812767SJames.Kremer@Sun.COM * Save the logs by walking through the entries in the response buffer.
17912767SJames.Kremer@Sun.COM *
18012767SJames.Kremer@Sun.COM * resp buffer looks like:
18112767SJames.Kremer@Sun.COM *
18212767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+
18312767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
18412767SJames.Kremer@Sun.COM * |Byte | | | | | | | | |
18512767SJames.Kremer@Sun.COM * |=====+====================================================================|
18612767SJames.Kremer@Sun.COM * | 0 | reserved | page code |
18712767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
18812767SJames.Kremer@Sun.COM * | 1 | Reserved |
18912767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
19012767SJames.Kremer@Sun.COM * | 2 |(MSB) Page Length(n-3) |
19112767SJames.Kremer@Sun.COM * | -- | |
19212767SJames.Kremer@Sun.COM * | 3 | (LSB) |
19312767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
19412767SJames.Kremer@Sun.COM * | 4 | Log Parameter (First)(Length X) |
19512767SJames.Kremer@Sun.COM * | -- | |
19612767SJames.Kremer@Sun.COM * | x+3 | |
19712767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
19812767SJames.Kremer@Sun.COM * |n-y+1| Log Parameter (Last)(Length y) |
19912767SJames.Kremer@Sun.COM * | -- | |
20012767SJames.Kremer@Sun.COM * | n | |
20112767SJames.Kremer@Sun.COM * +==========================================================================+
20212767SJames.Kremer@Sun.COM *
20312767SJames.Kremer@Sun.COM * Log parameter field looks like:
20412767SJames.Kremer@Sun.COM *
20512767SJames.Kremer@Sun.COM * +=====-========-========-========-========-========-========-========-=====+
20612767SJames.Kremer@Sun.COM * | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
20712767SJames.Kremer@Sun.COM * |Byte | | | | | | | | |
20812767SJames.Kremer@Sun.COM * |=====+====================================================================|
20912767SJames.Kremer@Sun.COM * | 0 |(MSB) Parameter Code |
21012767SJames.Kremer@Sun.COM * | -- | |
21112767SJames.Kremer@Sun.COM * | 1 | (LSB) |
21212767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
21312767SJames.Kremer@Sun.COM * | 2 | DU | DS | TSD | ETC | TMC | LBIN | LP |
21412767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
215*12843Stodd.mckenney@oracle.com * | 3 | Parameter Length(n-3) |
21612767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
21712767SJames.Kremer@Sun.COM * | 4 | Parameter Values |
21812767SJames.Kremer@Sun.COM * | -- | |
21912767SJames.Kremer@Sun.COM * | n | |
22012767SJames.Kremer@Sun.COM * |-----+--------------------------------------------------------------------|
22112767SJames.Kremer@Sun.COM */
22212767SJames.Kremer@Sun.COM
22312767SJames.Kremer@Sun.COM static int
save_logs(unsigned char * resp,ses_log_call_t * data)224*12843Stodd.mckenney@oracle.com save_logs(unsigned char *resp, ses_log_call_t *data)
22512767SJames.Kremer@Sun.COM {
226*12843Stodd.mckenney@oracle.com int k;
227*12843Stodd.mckenney@oracle.com int param_code; /* Parameter code */
228*12843Stodd.mckenney@oracle.com int param_len = 0; /* Paramter length */
229*12843Stodd.mckenney@oracle.com unsigned char *log_param_ptr; /* Log parameter pointer */
23012767SJames.Kremer@Sun.COM unsigned char *log_str_ptr; /* ptr to ascii str returend by expander */
23112767SJames.Kremer@Sun.COM
232*12843Stodd.mckenney@oracle.com char log_code[ENTRY_MAX_SIZE];
233*12843Stodd.mckenney@oracle.com char log_level[ENTRY_MAX_SIZE];
23412767SJames.Kremer@Sun.COM nvlist_t *entry;
23512767SJames.Kremer@Sun.COM char entry_num[15];
23612767SJames.Kremer@Sun.COM int match_found = 0;
237*12843Stodd.mckenney@oracle.com char save_buffer[MAX_LOG_ENTRY_SZ];
23812767SJames.Kremer@Sun.COM char entry_added = 0;
239*12843Stodd.mckenney@oracle.com int all_log_data_len;
240*12843Stodd.mckenney@oracle.com
241*12843Stodd.mckenney@oracle.com /*
242*12843Stodd.mckenney@oracle.com * Bytes 2 and 3 of response buffer contain the page length of
243*12843Stodd.mckenney@oracle.com * the log entries returned.
244*12843Stodd.mckenney@oracle.com */
245*12843Stodd.mckenney@oracle.com all_log_data_len = SCSI_READ16(&resp[2]);
246*12843Stodd.mckenney@oracle.com
247*12843Stodd.mckenney@oracle.com /*
248*12843Stodd.mckenney@oracle.com * Initialize log parameter pointer to point to first log entry.
249*12843Stodd.mckenney@oracle.com * The resp includes 4 bytes of header info and then log entries
250*12843Stodd.mckenney@oracle.com */
251*12843Stodd.mckenney@oracle.com log_param_ptr = &resp[0] + 4;
252*12843Stodd.mckenney@oracle.com
253*12843Stodd.mckenney@oracle.com /*
254*12843Stodd.mckenney@oracle.com * If multiple heads are reading the logs, it is possible that we
255*12843Stodd.mckenney@oracle.com * could be re-reading some of the same log entries plus some
256*12843Stodd.mckenney@oracle.com * new additional entries. Check to see if any entries in this read
257*12843Stodd.mckenney@oracle.com * contain the same log entry as the last entry we read last time.
258*12843Stodd.mckenney@oracle.com */
259*12843Stodd.mckenney@oracle.com if (data->last_log_entry != NULL &&
260*12843Stodd.mckenney@oracle.com (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE)) {
261*12843Stodd.mckenney@oracle.com /*
262*12843Stodd.mckenney@oracle.com * We have a valid log entry from a previous read log
263*12843Stodd.mckenney@oracle.com * operation.
264*12843Stodd.mckenney@oracle.com */
26512767SJames.Kremer@Sun.COM
26612767SJames.Kremer@Sun.COM
26712767SJames.Kremer@Sun.COM /*
268*12843Stodd.mckenney@oracle.com * Start walking each log entry in response buffer looking for
26912767SJames.Kremer@Sun.COM * a duplicate entry.
27012767SJames.Kremer@Sun.COM */
271*12843Stodd.mckenney@oracle.com for (k = 0; k < all_log_data_len; k += param_len) {
272*12843Stodd.mckenney@oracle.com /*
273*12843Stodd.mckenney@oracle.com * Calculate log entry length
274*12843Stodd.mckenney@oracle.com * Log param ptr [3] contains the log length minus the
275*12843Stodd.mckenney@oracle.com * header info which is 4 bytes so add that in.
276*12843Stodd.mckenney@oracle.com */
277*12843Stodd.mckenney@oracle.com param_len = log_param_ptr[3] + 4;
278*12843Stodd.mckenney@oracle.com
279*12843Stodd.mckenney@oracle.com if (param_len <= 4) {
28012767SJames.Kremer@Sun.COM /*
281*12843Stodd.mckenney@oracle.com * Only header information in this entry
282*12843Stodd.mckenney@oracle.com * process next log entry
28312767SJames.Kremer@Sun.COM */
284*12843Stodd.mckenney@oracle.com log_param_ptr += param_len;
285*12843Stodd.mckenney@oracle.com continue;
28612767SJames.Kremer@Sun.COM }
28712767SJames.Kremer@Sun.COM
28812767SJames.Kremer@Sun.COM
289*12843Stodd.mckenney@oracle.com /*
290*12843Stodd.mckenney@oracle.com * initialize log_str_ptr to point to string info
291*12843Stodd.mckenney@oracle.com * returned by expander
292*12843Stodd.mckenney@oracle.com * first 4 bytes of log parameter contains
293*12843Stodd.mckenney@oracle.com * 2 bytes of parameter code, 1 byte of Control data
294*12843Stodd.mckenney@oracle.com * and 1 byte for parameter length. Log string begins
295*12843Stodd.mckenney@oracle.com * after that so add 4 to log param ptr.
296*12843Stodd.mckenney@oracle.com */
297*12843Stodd.mckenney@oracle.com log_str_ptr = log_param_ptr + 4;
29812767SJames.Kremer@Sun.COM
299*12843Stodd.mckenney@oracle.com /*
300*12843Stodd.mckenney@oracle.com * Check to see if this is the
301*12843Stodd.mckenney@oracle.com * same line
302*12843Stodd.mckenney@oracle.com */
303*12843Stodd.mckenney@oracle.com if (strncmp((char *)log_str_ptr, data->last_log_entry,
304*12843Stodd.mckenney@oracle.com SES_LOG_VALID_LOG_SIZE) == 0) {
305*12843Stodd.mckenney@oracle.com /* Found an exact match */
306*12843Stodd.mckenney@oracle.com log_param_ptr += param_len;
307*12843Stodd.mckenney@oracle.com k += param_len;
308*12843Stodd.mckenney@oracle.com match_found = 1;
309*12843Stodd.mckenney@oracle.com break;
31012767SJames.Kremer@Sun.COM }
311*12843Stodd.mckenney@oracle.com log_param_ptr += param_len;
31212767SJames.Kremer@Sun.COM }
31312767SJames.Kremer@Sun.COM }
31412767SJames.Kremer@Sun.COM if (!match_found) {
315*12843Stodd.mckenney@oracle.com log_param_ptr = &resp[0] + 4;
316*12843Stodd.mckenney@oracle.com k = 0;
317*12843Stodd.mckenney@oracle.com }
318*12843Stodd.mckenney@oracle.com if (k == all_log_data_len) {
319*12843Stodd.mckenney@oracle.com /*
320*12843Stodd.mckenney@oracle.com * Either there was no log data or we have
321*12843Stodd.mckenney@oracle.com * already read these log entries.
322*12843Stodd.mckenney@oracle.com * Just return.
323*12843Stodd.mckenney@oracle.com */
324*12843Stodd.mckenney@oracle.com return (0);
325*12843Stodd.mckenney@oracle.com }
326*12843Stodd.mckenney@oracle.com
327*12843Stodd.mckenney@oracle.com /* Grab memory to return logs with */
328*12843Stodd.mckenney@oracle.com if (nvlist_alloc(&data->log_data, NV_UNIQUE_NAME, 0) != 0) {
329*12843Stodd.mckenney@oracle.com /* Couldn't alloc memory for nvlist */
330*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NVLIST_CREATE);
33112767SJames.Kremer@Sun.COM }
33212767SJames.Kremer@Sun.COM
333*12843Stodd.mckenney@oracle.com (void) memset(log_code, 0, sizeof (log_code));
334*12843Stodd.mckenney@oracle.com (void) memset(save_buffer, 0, sizeof (save_buffer));
335*12843Stodd.mckenney@oracle.com (void) memset(log_level, 0, sizeof (log_level));
336*12843Stodd.mckenney@oracle.com
337*12843Stodd.mckenney@oracle.com /*
338*12843Stodd.mckenney@oracle.com * Start saving new log entries
339*12843Stodd.mckenney@oracle.com * Walk the log data adding any new entries
340*12843Stodd.mckenney@oracle.com */
34112767SJames.Kremer@Sun.COM
342*12843Stodd.mckenney@oracle.com for (; k < all_log_data_len; k += param_len) {
343*12843Stodd.mckenney@oracle.com /*
344*12843Stodd.mckenney@oracle.com * Calculate log entry length
345*12843Stodd.mckenney@oracle.com * Log ptr [3] contains the log length minus the header info
346*12843Stodd.mckenney@oracle.com * which is 4 bytes so add that in
347*12843Stodd.mckenney@oracle.com */
348*12843Stodd.mckenney@oracle.com param_len = log_param_ptr[3] + 4;
349*12843Stodd.mckenney@oracle.com
350*12843Stodd.mckenney@oracle.com if (param_len <= 4) {
351*12843Stodd.mckenney@oracle.com /* Only header information in this entry */
352*12843Stodd.mckenney@oracle.com /* process next log entry */
353*12843Stodd.mckenney@oracle.com log_param_ptr += param_len;
354*12843Stodd.mckenney@oracle.com continue;
35512767SJames.Kremer@Sun.COM }
356*12843Stodd.mckenney@oracle.com
35712767SJames.Kremer@Sun.COM /*
358*12843Stodd.mckenney@oracle.com * initialize log_str_ptr to point to string info of the log
359*12843Stodd.mckenney@oracle.com * entry. First 4 bytes of log entry contains param code,
360*12843Stodd.mckenney@oracle.com * control byte, and length. Log string starts after that.
36112767SJames.Kremer@Sun.COM */
362*12843Stodd.mckenney@oracle.com log_str_ptr = log_param_ptr + 4;
36312767SJames.Kremer@Sun.COM
36412767SJames.Kremer@Sun.COM /*
36512767SJames.Kremer@Sun.COM * Format of log str is as follows
36612767SJames.Kremer@Sun.COM * "%8x %8x %8x %8x %8x %8x %8x %8x",
36712767SJames.Kremer@Sun.COM * log_entry.log_word0, log_entry.ts_u, log_entry.ts_l,
36812767SJames.Kremer@Sun.COM * log_entry.seq_num, log_entry.log_code, log_entry.log_word2,
36912767SJames.Kremer@Sun.COM * log_entry.log_word3, log_entry.log_word4
37012767SJames.Kremer@Sun.COM * following example has extra spaces removed to fit in 80 char
37112767SJames.Kremer@Sun.COM * 40004 0 42d5f5fe 185b 630002 fd0800 50800207 e482813
37212767SJames.Kremer@Sun.COM */
373*12843Stodd.mckenney@oracle.com
374*12843Stodd.mckenney@oracle.com (void) strncpy(save_buffer,
375*12843Stodd.mckenney@oracle.com (const char *)log_str_ptr,
376*12843Stodd.mckenney@oracle.com SES_LOG_VALID_LOG_SIZE);
377*12843Stodd.mckenney@oracle.com
378*12843Stodd.mckenney@oracle.com (void) strncpy(log_code,
379*12843Stodd.mckenney@oracle.com (const char *)log_str_ptr+SES_LOG_CODE_START,
380*12843Stodd.mckenney@oracle.com SES_LOG_SPECIFIC_ENTRY_SIZE);
381*12843Stodd.mckenney@oracle.com
382*12843Stodd.mckenney@oracle.com (void) strncpy(log_level,
383*12843Stodd.mckenney@oracle.com (const char *) log_str_ptr +
384*12843Stodd.mckenney@oracle.com SES_LOG_LEVEL_START, 1);
385*12843Stodd.mckenney@oracle.com
38612767SJames.Kremer@Sun.COM
387*12843Stodd.mckenney@oracle.com /* Add this entry to the nvlist log data */
388*12843Stodd.mckenney@oracle.com if (nvlist_alloc(&entry, NV_UNIQUE_NAME, 0) != 0) {
389*12843Stodd.mckenney@oracle.com /* Couldn't alloc space, return error */
390*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_UNIQUE);
391*12843Stodd.mckenney@oracle.com }
39212767SJames.Kremer@Sun.COM
39312767SJames.Kremer@Sun.COM
394*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_LOG, save_buffer) != 0) {
395*12843Stodd.mckenney@oracle.com /* Error adding string, return error */
396*12843Stodd.mckenney@oracle.com nvlist_free(entry);
397*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_LOG);
398*12843Stodd.mckenney@oracle.com }
39912767SJames.Kremer@Sun.COM
400*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_CODE, log_code) != 0) {
401*12843Stodd.mckenney@oracle.com /* Error adding string, return error */
402*12843Stodd.mckenney@oracle.com nvlist_free(entry);
403*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_CODE);
404*12843Stodd.mckenney@oracle.com }
405*12843Stodd.mckenney@oracle.com if (nvlist_add_string(entry, ENTRY_SEVERITY, log_level) != 0) {
406*12843Stodd.mckenney@oracle.com /* Error adding srtring, return error */
407*12843Stodd.mckenney@oracle.com nvlist_free(entry);
408*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_SEV);
409*12843Stodd.mckenney@oracle.com }
41012767SJames.Kremer@Sun.COM
411*12843Stodd.mckenney@oracle.com param_code = SCSI_READ16(&log_param_ptr[0]);
412*12843Stodd.mckenney@oracle.com
413*12843Stodd.mckenney@oracle.com (void) snprintf(entry_num, sizeof (entry_num),
414*12843Stodd.mckenney@oracle.com "%s%d", ENTRY_PREFIX, param_code);
41512767SJames.Kremer@Sun.COM
416*12843Stodd.mckenney@oracle.com if (nvlist_add_nvlist(data->log_data, entry_num, entry) != 0) {
417*12843Stodd.mckenney@oracle.com /* Error adding nvlist, return error */
418*12843Stodd.mckenney@oracle.com nvlist_free(entry);
419*12843Stodd.mckenney@oracle.com return (SES_LOG_FAILED_NV_ENTRY);
420*12843Stodd.mckenney@oracle.com }
421*12843Stodd.mckenney@oracle.com nvlist_free(entry);
42212767SJames.Kremer@Sun.COM
423*12843Stodd.mckenney@oracle.com entry_added = 1;
424*12843Stodd.mckenney@oracle.com (data->number_log_entries)++;
42512767SJames.Kremer@Sun.COM
426*12843Stodd.mckenney@oracle.com log_param_ptr += param_len;
42712767SJames.Kremer@Sun.COM
42812767SJames.Kremer@Sun.COM }
42912767SJames.Kremer@Sun.COM if (entry_added) {
43012767SJames.Kremer@Sun.COM /* Update the last log entry string with last one read */
431*12843Stodd.mckenney@oracle.com (void) strncpy(data->last_log_entry, save_buffer, MAXNAMELEN);
43212767SJames.Kremer@Sun.COM }
43312767SJames.Kremer@Sun.COM return (0);
43412767SJames.Kremer@Sun.COM }
43512767SJames.Kremer@Sun.COM
43612767SJames.Kremer@Sun.COM
43712767SJames.Kremer@Sun.COM
43812767SJames.Kremer@Sun.COM /* Setup struct to send command to device */
43912767SJames.Kremer@Sun.COM static void
set_scsi_pt_data_out(struct uscsi_cmd * uscsi,const unsigned char * dxferp,int dxfer_len)44012767SJames.Kremer@Sun.COM set_scsi_pt_data_out(struct uscsi_cmd *uscsi, const unsigned char *dxferp,
44112767SJames.Kremer@Sun.COM int dxfer_len)
44212767SJames.Kremer@Sun.COM {
44312767SJames.Kremer@Sun.COM if (dxfer_len > 0) {
44412767SJames.Kremer@Sun.COM uscsi->uscsi_bufaddr = (char *)dxferp;
44512767SJames.Kremer@Sun.COM uscsi->uscsi_buflen = dxfer_len;
44612767SJames.Kremer@Sun.COM uscsi->uscsi_flags = USCSI_WRITE | USCSI_ISOLATE |
44712767SJames.Kremer@Sun.COM USCSI_RQENABLE;
44812767SJames.Kremer@Sun.COM }
44912767SJames.Kremer@Sun.COM }
45012767SJames.Kremer@Sun.COM
45112767SJames.Kremer@Sun.COM /*
45212767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SENSE(10) command.
45312767SJames.Kremer@Sun.COM * Return:
45412767SJames.Kremer@Sun.COM * 0 for success
45512767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP -> invalid opcode
45612767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb
45712767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready
45812767SJames.Kremer@Sun.COM * -1 -> other failure
45912767SJames.Kremer@Sun.COM */
46012767SJames.Kremer@Sun.COM
46112767SJames.Kremer@Sun.COM static int
sg_ll_mode_sense10(int sg_fd,void * resp,int mx_resp_len)46212767SJames.Kremer@Sun.COM sg_ll_mode_sense10(int sg_fd, void * resp, int mx_resp_len)
46312767SJames.Kremer@Sun.COM {
46412767SJames.Kremer@Sun.COM int res, ret;
46512767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
46612767SJames.Kremer@Sun.COM {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
46712767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN];
46812767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi;
46912767SJames.Kremer@Sun.COM
47012767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0;
47112767SJames.Kremer@Sun.COM modesCmdBlk[2] = 0; /* page code 0 vendor specific */
47212767SJames.Kremer@Sun.COM modesCmdBlk[3] = 0;
47312767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char) ((mx_resp_len >> 8) & 0xff);
47412767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char) (mx_resp_len & 0xff);
47512767SJames.Kremer@Sun.COM
47612767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi);
47712767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
47812767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
47912767SJames.Kremer@Sun.COM set_scsi_pt_data_in(&uscsi, (unsigned char *) resp, mx_resp_len);
48012767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
48112767SJames.Kremer@Sun.COM if (res) {
48212767SJames.Kremer@Sun.COM ret = res;
48312767SJames.Kremer@Sun.COM } else {
48412767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status;
48512767SJames.Kremer@Sun.COM }
48612767SJames.Kremer@Sun.COM return (ret);
48712767SJames.Kremer@Sun.COM }
48812767SJames.Kremer@Sun.COM
48912767SJames.Kremer@Sun.COM /*
49012767SJames.Kremer@Sun.COM * Invokes a SCSI MODE SELECT(10) command.
49112767SJames.Kremer@Sun.COM * Return:
49212767SJames.Kremer@Sun.COM * 0 for success.
49312767SJames.Kremer@Sun.COM * SG_LIB_CAT_INVALID_OP for invalid opcode
49412767SJames.Kremer@Sun.COM * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb,
49512767SJames.Kremer@Sun.COM * SG_LIB_CAT_NOT_READY -> device not ready,
49612767SJames.Kremer@Sun.COM * -1 -> other failure
49712767SJames.Kremer@Sun.COM */
49812767SJames.Kremer@Sun.COM static int
sg_ll_mode_select10(int sg_fd,void * paramp,int param_len)49912767SJames.Kremer@Sun.COM sg_ll_mode_select10(int sg_fd, void * paramp, int param_len)
50012767SJames.Kremer@Sun.COM {
50112767SJames.Kremer@Sun.COM int res, ret;
50212767SJames.Kremer@Sun.COM unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] =
50312767SJames.Kremer@Sun.COM {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
50412767SJames.Kremer@Sun.COM unsigned char sense_b[SENSE_BUFF_LEN];
50512767SJames.Kremer@Sun.COM struct uscsi_cmd uscsi;
50612767SJames.Kremer@Sun.COM
50712767SJames.Kremer@Sun.COM
50812767SJames.Kremer@Sun.COM modesCmdBlk[1] = 0;
50912767SJames.Kremer@Sun.COM /*
510*12843Stodd.mckenney@oracle.com * modesCmdBlk 2 equal 0 PC 0 return current page code 0 return
51112767SJames.Kremer@Sun.COM * vendor specific
51212767SJames.Kremer@Sun.COM */
51312767SJames.Kremer@Sun.COM
51412767SJames.Kremer@Sun.COM modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff);
51512767SJames.Kremer@Sun.COM modesCmdBlk[8] = (unsigned char)(param_len & 0xff);
51612767SJames.Kremer@Sun.COM
51712767SJames.Kremer@Sun.COM construct_scsi_pt_obj(&uscsi);
51812767SJames.Kremer@Sun.COM
51912767SJames.Kremer@Sun.COM set_scsi_pt_cdb(&uscsi, modesCmdBlk, sizeof (modesCmdBlk));
52012767SJames.Kremer@Sun.COM set_scsi_pt_sense(&uscsi, sense_b, sizeof (sense_b));
52112767SJames.Kremer@Sun.COM set_scsi_pt_data_out(&uscsi, (unsigned char *) paramp, param_len);
52212767SJames.Kremer@Sun.COM res = do_scsi_pt(&uscsi, sg_fd, DEF_PT_TIMEOUT);
52312767SJames.Kremer@Sun.COM if (res) {
52412767SJames.Kremer@Sun.COM ret = res;
52512767SJames.Kremer@Sun.COM } else {
52612767SJames.Kremer@Sun.COM ret = uscsi.uscsi_status;
52712767SJames.Kremer@Sun.COM }
52812767SJames.Kremer@Sun.COM return (ret);
52912767SJames.Kremer@Sun.COM }
53012767SJames.Kremer@Sun.COM
53112767SJames.Kremer@Sun.COM
53212767SJames.Kremer@Sun.COM
53312767SJames.Kremer@Sun.COM /*
53412767SJames.Kremer@Sun.COM * MODE SENSE 10 commands yield a response that has block descriptors followed
53512767SJames.Kremer@Sun.COM * by mode pages. In most cases users are interested in the first mode page.
53612767SJames.Kremer@Sun.COM * This function returns the(byte) offset of the start of the first mode page.
53712767SJames.Kremer@Sun.COM * Returns >= 0 is successful or -1 if failure. If there is a failure
53812767SJames.Kremer@Sun.COM * a message is written to err_buff.
53912767SJames.Kremer@Sun.COM */
54012767SJames.Kremer@Sun.COM
54112767SJames.Kremer@Sun.COM /*
54212767SJames.Kremer@Sun.COM * return data looks like:
54312767SJames.Kremer@Sun.COM * Table 92 - Mode parameter header(10)
54412767SJames.Kremer@Sun.COM * Bit
54512767SJames.Kremer@Sun.COM * Byte
54612767SJames.Kremer@Sun.COM * 7 6 5 4 3 2 1 0
54712767SJames.Kremer@Sun.COM * ----------------------------------------------------------
54812767SJames.Kremer@Sun.COM * 0 MSB Data length
54912767SJames.Kremer@Sun.COM * 1 LSB Data length
55012767SJames.Kremer@Sun.COM * ----------------------------------------------------------
55112767SJames.Kremer@Sun.COM * 2 Medium type
55212767SJames.Kremer@Sun.COM * ----------------------------------------------------------
55312767SJames.Kremer@Sun.COM * 3 Device-specific parameter
55412767SJames.Kremer@Sun.COM * ----------------------------------------------------------
55512767SJames.Kremer@Sun.COM * 4 Reserved
55612767SJames.Kremer@Sun.COM * ----------------------------------------------------------
55712767SJames.Kremer@Sun.COM * 5 Reserved
55812767SJames.Kremer@Sun.COM * ----------------------------------------------------------
55912767SJames.Kremer@Sun.COM * 6 MSB block descriptor length
56012767SJames.Kremer@Sun.COM * 7 LSB block descriptor length
56112767SJames.Kremer@Sun.COM * ----------------------------------------------------------
56212767SJames.Kremer@Sun.COM * block desciptors....
56312767SJames.Kremer@Sun.COM * -----------------------
56412767SJames.Kremer@Sun.COM * mode sense page:
56512767SJames.Kremer@Sun.COM * 0 : ps Reserved : page Code
56612767SJames.Kremer@Sun.COM * 1 : Page Length(n-1)
56712767SJames.Kremer@Sun.COM * 2-N Mode parameters
56812767SJames.Kremer@Sun.COM */
56912767SJames.Kremer@Sun.COM static int
sg_mode_page_offset(const unsigned char * resp,int resp_len)570*12843Stodd.mckenney@oracle.com sg_mode_page_offset(const unsigned char *resp, int resp_len)
57112767SJames.Kremer@Sun.COM {
57212767SJames.Kremer@Sun.COM int bd_len;
57312767SJames.Kremer@Sun.COM int calc_len;
57412767SJames.Kremer@Sun.COM int offset;
57512767SJames.Kremer@Sun.COM
57612767SJames.Kremer@Sun.COM if ((NULL == resp) || (resp_len < 8)) {
57712767SJames.Kremer@Sun.COM /* Too short of a response buffer */
57812767SJames.Kremer@Sun.COM return (-1);
57912767SJames.Kremer@Sun.COM }
58012767SJames.Kremer@Sun.COM
58112767SJames.Kremer@Sun.COM calc_len = (resp[0] << 8) + resp[1] + 2;
58212767SJames.Kremer@Sun.COM bd_len = (resp[6] << 8) + resp[7];
58312767SJames.Kremer@Sun.COM
58412767SJames.Kremer@Sun.COM /* LongLBA doesn't change this calculation */
58512767SJames.Kremer@Sun.COM offset = bd_len + MODE10_RESP_HDR_LEN;
58612767SJames.Kremer@Sun.COM
58712767SJames.Kremer@Sun.COM if ((offset + 2) > resp_len) {
588*12843Stodd.mckenney@oracle.com /* Given response length to small */
58912767SJames.Kremer@Sun.COM offset = -1;
59012767SJames.Kremer@Sun.COM } else if ((offset + 2) > calc_len) {
591*12843Stodd.mckenney@oracle.com /* Calculated response length too small */
59212767SJames.Kremer@Sun.COM offset = -1;
59312767SJames.Kremer@Sun.COM }
59412767SJames.Kremer@Sun.COM return (offset);
59512767SJames.Kremer@Sun.COM }
59612767SJames.Kremer@Sun.COM
59712767SJames.Kremer@Sun.COM /*
59812767SJames.Kremer@Sun.COM * Clear logs
59912767SJames.Kremer@Sun.COM */
60012767SJames.Kremer@Sun.COM static int
clear_log(int sg_fd,ses_log_call_t * data)601*12843Stodd.mckenney@oracle.com clear_log(int sg_fd, ses_log_call_t *data)
60212767SJames.Kremer@Sun.COM {
60312767SJames.Kremer@Sun.COM
60412767SJames.Kremer@Sun.COM int res, alloc_len, off;
60512767SJames.Kremer@Sun.COM int md_len;
60612767SJames.Kremer@Sun.COM int read_in_len = 0;
607*12843Stodd.mckenney@oracle.com unsigned char ref_md[MAX_ALLOC_LEN];
60812767SJames.Kremer@Sun.COM struct log_clear_control_struct clear_data;
60912767SJames.Kremer@Sun.COM long myhostid;
61012767SJames.Kremer@Sun.COM int error = 0;
611*12843Stodd.mckenney@oracle.com long poll_time;
612*12843Stodd.mckenney@oracle.com char seq_num_str[10];
613*12843Stodd.mckenney@oracle.com unsigned long seq_num = 0;
61412767SJames.Kremer@Sun.COM
61512767SJames.Kremer@Sun.COM (void) memset(&clear_data, 0, sizeof (clear_data));
61612767SJames.Kremer@Sun.COM
61712767SJames.Kremer@Sun.COM clear_data.pageControls = 0x40;
61812767SJames.Kremer@Sun.COM clear_data.subpage_code = 0;
61912767SJames.Kremer@Sun.COM clear_data.page_lengthLower = 0x16;
62012767SJames.Kremer@Sun.COM
62112767SJames.Kremer@Sun.COM myhostid = gethostid();
62212767SJames.Kremer@Sun.COM /* 0 -> 11 are memset to 0 */
62312767SJames.Kremer@Sun.COM clear_data.host_id[12] = (myhostid & 0xff000000) >> 24;
62412767SJames.Kremer@Sun.COM clear_data.host_id[13] = (myhostid & 0xff0000) >> 16;
62512767SJames.Kremer@Sun.COM clear_data.host_id[14] = (myhostid & 0xff00) >> 8;
62612767SJames.Kremer@Sun.COM clear_data.host_id[15] = myhostid & 0xff;
62712767SJames.Kremer@Sun.COM
628*12843Stodd.mckenney@oracle.com /*
629*12843Stodd.mckenney@oracle.com * convert nanosecond time to seconds
630*12843Stodd.mckenney@oracle.com */
631*12843Stodd.mckenney@oracle.com poll_time = data->poll_time / 1000000000;
632*12843Stodd.mckenney@oracle.com /* Add 5 minutes to poll time to allow for data retrieval time */
63312767SJames.Kremer@Sun.COM poll_time = poll_time + 300;
63412767SJames.Kremer@Sun.COM clear_data.timeout[0] = (poll_time & 0xff00) >> 8;
63512767SJames.Kremer@Sun.COM clear_data.timeout[1] = poll_time & 0xff;
63612767SJames.Kremer@Sun.COM
637*12843Stodd.mckenney@oracle.com /*
638*12843Stodd.mckenney@oracle.com * retrieve the last read sequence number from the last
639*12843Stodd.mckenney@oracle.com * log entry read.
640*12843Stodd.mckenney@oracle.com */
641*12843Stodd.mckenney@oracle.com if (data->last_log_entry != NULL &&
642*12843Stodd.mckenney@oracle.com (strlen(data->last_log_entry) == SES_LOG_VALID_LOG_SIZE)) {
643*12843Stodd.mckenney@oracle.com /*
644*12843Stodd.mckenney@oracle.com * We have a valid log entry from a previous read log
645*12843Stodd.mckenney@oracle.com * operation.
646*12843Stodd.mckenney@oracle.com */
647*12843Stodd.mckenney@oracle.com (void) strncpy(seq_num_str,
648*12843Stodd.mckenney@oracle.com (const char *) data->last_log_entry +
649*12843Stodd.mckenney@oracle.com SES_LOG_SEQ_NUM_START, 8);
650*12843Stodd.mckenney@oracle.com seq_num = strtoul(seq_num_str, 0, 16);
651*12843Stodd.mckenney@oracle.com }
65212767SJames.Kremer@Sun.COM clear_data.seq_clear[0] = (seq_num & 0xff000000) >> 24;
65312767SJames.Kremer@Sun.COM clear_data.seq_clear[1] = (seq_num & 0xff0000) >> 16;
65412767SJames.Kremer@Sun.COM clear_data.seq_clear[2] = (seq_num & 0xff00) >> 8;
65512767SJames.Kremer@Sun.COM clear_data.seq_clear[3] = (seq_num & 0xff);
65612767SJames.Kremer@Sun.COM
65712767SJames.Kremer@Sun.COM read_in_len = sizeof (clear_data);
65812767SJames.Kremer@Sun.COM
65912767SJames.Kremer@Sun.COM
66012767SJames.Kremer@Sun.COM /* do MODE SENSE to fetch current values */
661*12843Stodd.mckenney@oracle.com (void) memset(ref_md, 0, MAX_ALLOC_LEN);
662*12843Stodd.mckenney@oracle.com alloc_len = MAX_ALLOC_LEN;
66312767SJames.Kremer@Sun.COM
66412767SJames.Kremer@Sun.COM
66512767SJames.Kremer@Sun.COM res = sg_ll_mode_sense10(sg_fd, ref_md, alloc_len);
66612767SJames.Kremer@Sun.COM if (0 != res) {
66712767SJames.Kremer@Sun.COM /* Error during mode sense */
66812767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE;
66912767SJames.Kremer@Sun.COM return (error);
67012767SJames.Kremer@Sun.COM }
67112767SJames.Kremer@Sun.COM
67212767SJames.Kremer@Sun.COM /* Setup mode Select to clear logs */
673*12843Stodd.mckenney@oracle.com off = sg_mode_page_offset(ref_md, alloc_len);
67412767SJames.Kremer@Sun.COM if (off < 0) {
67512767SJames.Kremer@Sun.COM /* Mode page offset error */
67612767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SENSE_OFFSET;
67712767SJames.Kremer@Sun.COM return (error);
67812767SJames.Kremer@Sun.COM }
67912767SJames.Kremer@Sun.COM md_len = (ref_md[0] << 8) + ref_md[1] + 2;
68012767SJames.Kremer@Sun.COM
68112767SJames.Kremer@Sun.COM ref_md[0] = 0;
68212767SJames.Kremer@Sun.COM ref_md[1] = 0;
68312767SJames.Kremer@Sun.COM
68412767SJames.Kremer@Sun.COM if (md_len > alloc_len) {
68512767SJames.Kremer@Sun.COM /* Data length to large */
68612767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_DATA_LEN;
68712767SJames.Kremer@Sun.COM return (error);
68812767SJames.Kremer@Sun.COM }
68912767SJames.Kremer@Sun.COM
69012767SJames.Kremer@Sun.COM if ((md_len - off) != read_in_len) {
69112767SJames.Kremer@Sun.COM /* Content length not correct */
69212767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_BAD_CONTENT_LEN;
69312767SJames.Kremer@Sun.COM return (error);
69412767SJames.Kremer@Sun.COM }
69512767SJames.Kremer@Sun.COM
69612767SJames.Kremer@Sun.COM if ((clear_data.pageControls & 0x40) != (ref_md[off] & 0x40)) {
69712767SJames.Kremer@Sun.COM /* reference model doesn't have use subpage format bit set */
69812767SJames.Kremer@Sun.COM /* Even though it should have */
69912767SJames.Kremer@Sun.COM /* don't send the command */
700*12843Stodd.mckenney@oracle.com error = SES_LOG_FAILED_FORMAT_PAGE_ERR;
70112767SJames.Kremer@Sun.COM return (error);
70212767SJames.Kremer@Sun.COM }
70312767SJames.Kremer@Sun.COM
704*12843Stodd.mckenney@oracle.com (void) memcpy(ref_md + off, (const void *) &clear_data,
70512767SJames.Kremer@Sun.COM sizeof (clear_data));
70612767SJames.Kremer@Sun.COM
70712767SJames.Kremer@Sun.COM res = sg_ll_mode_select10(sg_fd, ref_md, md_len);
70812767SJames.Kremer@Sun.COM if (res != 0) {
70912767SJames.Kremer@Sun.COM error = SES_LOG_FAILED_MODE_SELECT;
71012767SJames.Kremer@Sun.COM return (error);
71112767SJames.Kremer@Sun.COM }
71212767SJames.Kremer@Sun.COM
71312767SJames.Kremer@Sun.COM return (error);
71412767SJames.Kremer@Sun.COM }
71512767SJames.Kremer@Sun.COM /*
71612767SJames.Kremer@Sun.COM * Gather data from given device.
71712767SJames.Kremer@Sun.COM */
71812767SJames.Kremer@Sun.COM static int
gather_data(char * device_name,ses_log_call_t * data)719*12843Stodd.mckenney@oracle.com gather_data(char *device_name, ses_log_call_t *data)
72012767SJames.Kremer@Sun.COM {
72112767SJames.Kremer@Sun.COM int sg_fd;
722*12843Stodd.mckenney@oracle.com int resp_len, res;
723*12843Stodd.mckenney@oracle.com unsigned char rsp_buff[MAX_ALLOC_LEN];
72412767SJames.Kremer@Sun.COM int error;
72512767SJames.Kremer@Sun.COM
72612767SJames.Kremer@Sun.COM /* Open device */
72712767SJames.Kremer@Sun.COM if ((sg_fd = open_device(device_name)) < 0) {
72812767SJames.Kremer@Sun.COM /* Failed to open device */
72912767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_OPEN_DEVICE);
73012767SJames.Kremer@Sun.COM }
73112767SJames.Kremer@Sun.COM
73212767SJames.Kremer@Sun.COM /* Read the logs */
73312767SJames.Kremer@Sun.COM (void) memset(rsp_buff, 0, sizeof (rsp_buff));
73412767SJames.Kremer@Sun.COM resp_len = 0x8000; /* Maximum size available to read */
73512767SJames.Kremer@Sun.COM res = read_log(sg_fd, rsp_buff, resp_len);
73612767SJames.Kremer@Sun.COM
737*12843Stodd.mckenney@oracle.com if (res != 0) {
73812767SJames.Kremer@Sun.COM /* Some sort of Error during read of logs */
739*12843Stodd.mckenney@oracle.com (void) close(sg_fd);
74012767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_TO_READ_DEVICE);
74112767SJames.Kremer@Sun.COM }
74212767SJames.Kremer@Sun.COM
74312767SJames.Kremer@Sun.COM /* Save the logs */
744*12843Stodd.mckenney@oracle.com error = save_logs(rsp_buff, data);
74512767SJames.Kremer@Sun.COM if (error != 0) {
746*12843Stodd.mckenney@oracle.com (void) close(sg_fd);
74712767SJames.Kremer@Sun.COM return (error);
74812767SJames.Kremer@Sun.COM }
749*12843Stodd.mckenney@oracle.com /* Clear the logs */
750*12843Stodd.mckenney@oracle.com error = clear_log(sg_fd, data);
75112767SJames.Kremer@Sun.COM
75212767SJames.Kremer@Sun.COM (void) close(sg_fd);
75312767SJames.Kremer@Sun.COM
75412767SJames.Kremer@Sun.COM return (error);
75512767SJames.Kremer@Sun.COM }
75612767SJames.Kremer@Sun.COM
75712767SJames.Kremer@Sun.COM /*
75812767SJames.Kremer@Sun.COM * Access the SES target identified by the indicated path. Read the logs
75912767SJames.Kremer@Sun.COM * and return them in a nvlist.
76012767SJames.Kremer@Sun.COM */
76112767SJames.Kremer@Sun.COM int
access_ses_log(ses_log_call_t * data)762*12843Stodd.mckenney@oracle.com access_ses_log(ses_log_call_t *data)
76312767SJames.Kremer@Sun.COM {
76412767SJames.Kremer@Sun.COM char real_path[MAXPATHLEN];
76512767SJames.Kremer@Sun.COM struct stat buffer;
76612767SJames.Kremer@Sun.COM int error;
76712767SJames.Kremer@Sun.COM
768*12843Stodd.mckenney@oracle.com /* Initialize return data */
769*12843Stodd.mckenney@oracle.com data->log_data = NULL;
770*12843Stodd.mckenney@oracle.com data->number_log_entries = 0;
771*12843Stodd.mckenney@oracle.com
77212767SJames.Kremer@Sun.COM if (data->target_path == NULL) {
77312767SJames.Kremer@Sun.COM /* NULL Target path, return error */
77412767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_NULL_TARGET_PATH);
77512767SJames.Kremer@Sun.COM }
77612767SJames.Kremer@Sun.COM
77712767SJames.Kremer@Sun.COM /* Try to find a valid path */
77812767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:ses",
77912767SJames.Kremer@Sun.COM data->target_path);
78012767SJames.Kremer@Sun.COM
78112767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) {
78212767SJames.Kremer@Sun.COM
78312767SJames.Kremer@Sun.COM (void) snprintf(real_path, sizeof (real_path), "/devices%s:0",
78412767SJames.Kremer@Sun.COM data->target_path);
78512767SJames.Kremer@Sun.COM if (stat(real_path, &buffer) != 0) {
78612767SJames.Kremer@Sun.COM /* Couldn't find a path that exists */
78712767SJames.Kremer@Sun.COM return (SES_LOG_FAILED_BAD_TARGET_PATH);
78812767SJames.Kremer@Sun.COM }
78912767SJames.Kremer@Sun.COM }
79012767SJames.Kremer@Sun.COM
791*12843Stodd.mckenney@oracle.com error = gather_data(real_path, data);
79212767SJames.Kremer@Sun.COM
79312767SJames.Kremer@Sun.COM /* Update the size of log entries being returned */
79412767SJames.Kremer@Sun.COM data->size_of_log_entries =
79512767SJames.Kremer@Sun.COM data->number_log_entries * SES_LOG_VALID_LOG_SIZE;
79612767SJames.Kremer@Sun.COM
79712767SJames.Kremer@Sun.COM return (error);
79812767SJames.Kremer@Sun.COM }
799