#include <stdlib.h>
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/scsi/scsi.h>
#include <nl_types.h>
#include <strings.h>
#include <sys/ddi.h>
#include <l_common.h>
#include <stgcom.h>
#include <l_error.h>
#include <a_state.h>
#include <a5k.h>
#define VERBPRINT if (verbose) (void) printf
static int
d_offline_drive(struct dlist *dl, int *bsy_res_flag_p, int verbose)
{
char dev_path1[MAXPATHLEN];
devctl_hdl_t devhdl;
for (; dl != NULL; dl = dl->next) {
(void) strcpy(dev_path1, dl->dev_path);
if ((devhdl = devctl_device_acquire(dev_path1,
DC_EXCL)) == NULL) {
if (errno != EBUSY) {
return (L_ACQUIRE_FAIL);
}
}
if (devctl_device_offline(devhdl) != 0) {
*bsy_res_flag_p = 1;
(void) devctl_release(devhdl);
return (0);
}
E_DPRINTF(" d_offline_drive: Offline succeeded:/n "
"%s\n", dev_path1);
(void) devctl_release(devhdl);
}
return (0);
}
int
l_check_busy_reserv_bp(char *ses_path, int front_flag,
int port_a_flag, int *bsy_res_flag_p, int verbose)
{
int err, i;
L_state *l_state = NULL;
struct dlist *p_list;
if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
return (L_MALLOC_FAILED);
}
if (err = l_get_status(ses_path, l_state, verbose)) {
(void) l_free_lstate(&l_state);
return (err);
}
for (i = 0; i < (int)l_state->total_num_drv/2; i++) {
if ((front_flag &&
(l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] &
L_RESERVED)) || (!front_flag &&
(l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] &
L_RESERVED))) {
*bsy_res_flag_p = 1;
(void) l_free_lstate(&l_state);
return (0);
}
}
for (i = 0; i < (int)l_state->total_num_drv/2; i++) {
if (front_flag) {
if (port_a_flag) {
if ((err = g_get_port_multipath(
l_state->drv_front[i].g_disk_state.port_a_wwn_s,
&p_list, verbose)) != 0) {
(void) l_free_lstate(&l_state);
return (err);
}
} else {
if ((err = g_get_port_multipath(
l_state->drv_front[i].g_disk_state.port_b_wwn_s,
&p_list, verbose)) != 0) {
(void) l_free_lstate(&l_state);
return (err);
}
}
} else {
if (port_a_flag) {
if ((err = g_get_port_multipath(
l_state->drv_rear[i].g_disk_state.port_a_wwn_s,
&p_list, verbose)) != 0) {
(void) l_free_lstate(&l_state);
return (err);
}
} else {
if ((err = g_get_port_multipath(
l_state->drv_rear[i].g_disk_state.port_b_wwn_s,
&p_list, verbose)) != 0) {
(void) l_free_lstate(&l_state);
return (err);
}
}
}
if (err = d_offline_drive(p_list,
bsy_res_flag_p, verbose)) {
(void) g_free_multipath(p_list);
(void) l_free_lstate(&l_state);
return (err);
}
(void) g_free_multipath(p_list);
}
(void) l_free_lstate(&l_state);
return (0);
}
int
l_bp_bypass_enable(char *ses_path, int bypass_flag, int port_a_flag,
int front_flag, int force_flag, int verbose)
{
int fd, i;
int nobj = 0;
ses_objarg obj;
ses_object *all_objp = NULL, *all_objp_save = NULL;
int found = 0;
Bp_elem_st *bp;
char msg[MAXPATHLEN];
int bsy_res_flag = 0;
int err;
if (ses_path == NULL) {
return (L_NO_SES_PATH);
}
if (!force_flag && bypass_flag) {
if (err = l_check_busy_reserv_bp(ses_path,
front_flag, port_a_flag, &bsy_res_flag, verbose)) {
return (err);
}
if (bsy_res_flag) {
return (L_BP_BUSY_RESERVED);
}
}
if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
return (errno);
}
if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t)&nobj) < 0) {
(void) close(fd);
return (errno);
}
if (nobj == 0) {
(void) close(fd);
return (L_IB_NO_ELEM_FOUND);
}
E_DPRINTF(" l_ib_bypass_bp: Number of SES objects: 0x%x\n",
nobj);
if ((all_objp = g_zalloc((nobj + 1) * sizeof (ses_object))) == NULL) {
(void) close(fd);
return (errno);
}
all_objp_save = all_objp;
if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t)all_objp) < 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (errno);
}
for (i = 0; i < nobj; i++, all_objp++) {
E_DPRINTF(" ID 0x%x\t Element type 0x%x\n",
all_objp->obj_id, all_objp->elem_type);
if (all_objp->elem_type == ELM_TYP_BP) {
found++;
break;
}
}
if (found == 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (L_NO_BP_ELEM_FOUND);
}
if (verbose) {
obj.obj_id = all_objp->obj_id;
if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (errno);
}
(void) fprintf(stdout, MSGSTR(8000,
" Front backplane status: "));
bp = (struct bp_element_status *)&obj.cstat[0];
l_element_msg_string(bp->code, msg);
(void) fprintf(stdout, "%s\n", msg);
if (bp->byp_a_enabled || bp->en_bypass_a) {
(void) fprintf(stdout, " ");
(void) fprintf(stdout,
MSGSTR(130, "Bypass A enabled"));
(void) fprintf(stdout, ".\n");
}
if (bp->byp_b_enabled || bp->en_bypass_b) {
(void) fprintf(stdout, " ");
(void) fprintf(stdout,
MSGSTR(129, "Bypass B enabled"));
(void) fprintf(stdout, ".\n");
}
all_objp++;
obj.obj_id = all_objp->obj_id;
all_objp--;
if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (errno);
}
(void) fprintf(stdout, MSGSTR(8001,
" Rear backplane status: "));
bp = (struct bp_element_status *)&obj.cstat[0];
l_element_msg_string(bp->code, msg);
(void) fprintf(stdout, "%s\n", msg);
if (bp->byp_a_enabled || bp->en_bypass_a) {
(void) fprintf(stdout, " ");
(void) fprintf(stdout,
MSGSTR(130, "Bypass A enabled"));
(void) fprintf(stdout, ".\n");
}
if (bp->byp_b_enabled || bp->en_bypass_b) {
(void) fprintf(stdout, " ");
(void) fprintf(stdout,
MSGSTR(129, "Bypass B enabled"));
(void) fprintf(stdout, ".\n");
}
}
if (!front_flag) {
all_objp++;
}
obj.obj_id = all_objp->obj_id;
if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t)&obj) < 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (errno);
}
bp = (struct bp_element_status *)&obj.cstat[0];
bp->select = 1;
bp->code = 0;
if (port_a_flag) {
bp->en_bypass_a = bypass_flag;
} else {
bp->en_bypass_b = bypass_flag;
}
if (getenv("_LUX_E_DEBUG") != NULL) {
(void) printf(" Sending this structure to ID 0x%x"
" of type 0x%x\n",
obj.obj_id, all_objp->elem_type);
for (i = 0; i < 4; i++) {
(void) printf(" Byte %d 0x%x\n", i,
obj.cstat[i]);
}
}
if (ioctl(fd, SESIOC_SETOBJSTAT, (caddr_t)&obj) < 0) {
(void) close(fd);
(void) g_destroy_data(all_objp_save);
return (errno);
}
(void) g_destroy_data(all_objp_save);
(void) close(fd);
return (0);
}
int
l_dev_bypass_enable(struct path_struct *path_struct, int bypass_flag,
int force_flag, int port_a_flag, int verbose)
{
gfc_map_t map;
char ses_path[MAXPATHLEN];
uchar_t *page_buf;
int err, fd, front_index, rear_index, offset;
int pathcnt = 1;
unsigned short page_len;
struct device_element *elem;
L_state *l_state = NULL;
struct device_element status;
int bsy_flag = 0, i, f_flag;
struct dlist *p_list;
char temppath[MAXPATHLEN];
mp_pathlist_t pathlist;
int p_pw = 0, p_on = 0, p_st = 0;
L_inquiry inq;
if (path_struct == NULL) {
return (L_INVALID_PATH_FORMAT);
}
if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
return (L_MALLOC_FAILED);
}
map.dev_addr = (gfc_port_dev_info_t *)NULL;
(void) strcpy(temppath, path_struct->p_physical_path);
if ((strstr(path_struct->p_physical_path, SCSI_VHCI) != NULL) &&
(!g_get_pathlist(temppath, &pathlist))) {
pathcnt = pathlist.path_count;
p_pw = p_on = p_st = 0;
for (i = 0; i < pathcnt; i++) {
if (pathlist.path_info[i].path_state <
MAXPATHSTATE) {
if (strstr(pathlist.path_info[i].
path_addr,
path_struct->argv) != NULL) {
p_pw = i;
break;
}
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
p_on = i;
}
if (pathlist.path_info[i].path_state ==
MDI_PATHINFO_STATE_STANDBY) {
p_st = i;
}
}
}
if (strstr(pathlist.path_info[p_pw].path_addr,
path_struct->argv) != NULL) {
(void) strcpy(temppath,
pathlist.path_info[p_pw].path_hba);
} else if (pathlist.path_info[p_on].path_state ==
MDI_PATHINFO_STATE_ONLINE) {
(void) strcpy(temppath,
pathlist.path_info[p_on].path_hba);
} else {
(void) strcpy(temppath,
pathlist.path_info[p_st].path_hba);
}
free(pathlist.path_info);
(void) strcat(temppath, FC_CTLR);
}
if (!path_struct->ib_path_flag) {
if (err = g_get_dev_map(temppath, &map, verbose)) {
(void) l_free_lstate(&l_state);
return (err);
}
if (err = l_get_ses_path(path_struct->p_physical_path,
ses_path, &map, verbose)) {
(void) l_free_lstate(&l_state);
free((void *)map.dev_addr);
return (err);
}
} else {
(void) strcpy(ses_path, path_struct->p_physical_path);
}
if (!path_struct->slot_valid) {
if ((map.dev_addr == (gfc_port_dev_info_t *)NULL) &&
((err = g_get_dev_map(temppath,
&map, verbose)) != 0)) {
(void) l_free_lstate(&l_state);
return (err);
}
if ((err = l_get_ses_path(path_struct->p_physical_path,
ses_path, &map, verbose)) != 0) {
(void) l_free_lstate(&l_state);
free((void *)map.dev_addr);
return (err);
}
if ((err = l_get_status(ses_path, l_state, verbose)) != 0) {
(void) l_free_lstate(&l_state);
free((void *)map.dev_addr);
return (err);
}
if ((err = l_get_slot(path_struct, l_state, verbose)) != 0) {
(void) l_free_lstate(&l_state);
free((void *)map.dev_addr);
return (err);
}
}
if (map.dev_addr != (gfc_port_dev_info_t *)NULL) {
free((void *)map.dev_addr);
}
if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) {
(void) l_free_lstate(&l_state);
return (errno);
}
if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (errno);
}
if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
L_PAGE_2, verbose)) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
if (err = l_get_status(ses_path, l_state, verbose)) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
if ((!(force_flag | path_struct->ib_path_flag)) &&
bypass_flag) {
i = path_struct->slot;
f_flag = path_struct->f_flag;
if ((f_flag &&
(l_state->drv_front[i].g_disk_state.d_state_flags[port_a_flag] &
L_RESERVED)) || (!f_flag &&
(l_state->drv_rear[i].g_disk_state.d_state_flags[port_a_flag] &
L_RESERVED))) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (L_BP_RESERVED);
}
if (f_flag) {
if (port_a_flag) {
if ((err = g_get_port_multipath(
l_state->drv_front[i].g_disk_state.port_a_wwn_s,
&p_list, verbose)) != 0) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
} else {
if ((err = g_get_port_multipath(
l_state->drv_front[i].g_disk_state.port_b_wwn_s,
&p_list, verbose)) != 0) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
}
} else {
if (port_a_flag) {
if ((err = g_get_port_multipath(
l_state->drv_rear[i].g_disk_state.port_a_wwn_s,
&p_list, verbose)) != 0) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
} else {
if ((err = g_get_port_multipath(
l_state->drv_rear[i].g_disk_state.port_b_wwn_s,
&p_list, verbose)) != 0) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
}
}
if (err = d_offline_drive(p_list,
&bsy_flag, verbose)) {
(void) g_free_multipath(p_list);
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
(void) g_free_multipath(p_list);
if (bsy_flag) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (L_BP_BUSY);
}
}
if (err = l_get_disk_element_index(l_state, &front_index,
&rear_index)) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
if (g_get_inquiry(ses_path, &inq)) {
return (L_SCSI_ERROR);
}
front_index++;
if ((strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME,
strlen(DAK_OFF_NAME)) == 0) ||
(strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR,
strlen(DAK_PROD_STR)) == 0)) {
rear_index += (MAX_DRIVES_DAK/2) + 1;
} else {
rear_index++;
}
if (path_struct->f_flag) {
offset = (8 + (front_index + path_struct->slot)*4);
} else {
offset = (8 + (rear_index + path_struct->slot)*4);
}
elem = (struct device_element *)(page_buf + offset);
bcopy((const void *)elem, (void *)&status,
sizeof (struct device_element));
bzero(elem, sizeof (struct device_element));
elem->select = 1;
elem->dev_off = status.dev_off;
elem->en_bypass_a = status.en_bypass_a;
elem->en_bypass_b = status.en_bypass_b;
if (port_a_flag) {
elem->en_bypass_a = bypass_flag;
} else {
elem->en_bypass_b = bypass_flag;
}
if (getenv("_LUX_E_DEBUG") != NULL) {
g_dump(" l_dev_bypass_enable: Updating LRC circuit state:\n"
" Device Status Element ",
(uchar_t *)elem, sizeof (struct device_element),
HEX_ONLY);
(void) fprintf(stdout, " for device at location:"
" enclosure:%s slot:%d %s\n",
l_state->ib_tbl.enclosure_name,
path_struct->slot,
path_struct->f_flag ? "front" : "rear");
}
if (err = g_scsi_send_diag_cmd(fd,
(uchar_t *)page_buf, page_len)) {
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (err);
}
(void) close(fd);
(void) g_destroy_data(page_buf);
(void) l_free_lstate(&l_state);
return (0);
}
int
d_p_enable(char *path, int verbose)
{
return (0);
}
int
d_p_bypass(char *path, int verbose)
{
return (0);
}