#include <sys/types.h>
#include <sys/ioctl.h>
#include <atf-c.h>
#include <fcntl.h>
#include <glob.h>
#include <regex.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <cam/scsi/scsi_enc.h>
#include "common.h"
static void
for_one_ses_dev(ses_cb cb)
{
glob_t g;
int fd, r;
g.gl_pathc = 0;
g.gl_pathv = NULL;
g.gl_offs = 0;
r = glob("/dev/ses*", GLOB_NOCHECK | GLOB_NOSORT, NULL, &g);
ATF_REQUIRE_EQ(r, 0);
if (g.gl_matchc == 0)
return;
fd = open(g.gl_pathv[0], O_RDWR);
ATF_REQUIRE(fd >= 0);
cb(g.gl_pathv[0], fd);
close(fd);
globfree(&g);
}
static bool
do_setelmstat(const char *devname __unused, int fd)
{
encioc_element_t *map;
unsigned elm_idx;
unsigned nobj;
int r;
elm_type_t last_elm_type = -1;
r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
ATF_REQUIRE_EQ(r, 0);
map = calloc(nobj, sizeof(encioc_element_t));
ATF_REQUIRE(map != NULL);
r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
encioc_elm_status_t elmstat;
struct ses_ctrl_dev_slot *cslot;
if (last_elm_type != map[elm_idx].elm_type) {
last_elm_type = map[elm_idx].elm_type;
continue;
}
elmstat.elm_idx = elm_idx;
if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
{
r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
ATF_REQUIRE_EQ(r, 0);
ses_status_to_ctrl(map[elm_idx].elm_type,
&elmstat.cstat[0]);
cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
ses_ctrl_common_set_select(&cslot->common, 1);
ses_ctrl_dev_slot_set_rqst_ident(cslot, 1);
r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
ATF_REQUIRE_EQ(r, 0);
}
}
last_elm_type = -1;
for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
encioc_elm_status_t elmstat;
struct ses_status_dev_slot *sslot =
(struct ses_status_dev_slot*)&elmstat.cstat[0];
if (last_elm_type != map[elm_idx].elm_type) {
last_elm_type = map[elm_idx].elm_type;
continue;
}
elmstat.elm_idx = elm_idx;
if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
{
int i;
for (i = 0; i < 10; i++) {
r = ioctl(fd, ENCIOC_GETELMSTAT,
(caddr_t)&elmstat);
ATF_REQUIRE_EQ(r, 0);
if (0 == ses_status_dev_slot_get_ident(sslot)) {
usleep(100000);
}
}
ATF_CHECK(ses_status_dev_slot_get_ident(sslot) != 0);
}
}
free(map);
return (true);
}
static bool
do_setelmstat_cleanup(const char *devname __unused, int fd __unused)
{
encioc_element_t *map;
unsigned elm_idx;
unsigned nobj;
int r;
elm_type_t last_elm_type = -1;
r = ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj);
ATF_REQUIRE_EQ(r, 0);
map = calloc(nobj, sizeof(encioc_element_t));
ATF_REQUIRE(map != NULL);
r = ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) map);
ATF_REQUIRE_EQ(r, 0);
for (elm_idx = 0; elm_idx < nobj; elm_idx++) {
encioc_elm_status_t elmstat;
struct ses_ctrl_dev_slot *cslot;
if (last_elm_type != map[elm_idx].elm_type) {
last_elm_type = map[elm_idx].elm_type;
continue;
}
elmstat.elm_idx = elm_idx;
if (map[elm_idx].elm_type == ELMTYP_DEVICE ||
map[elm_idx].elm_type == ELMTYP_ARRAY_DEV)
{
r = ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t)&elmstat);
ATF_REQUIRE_EQ(r, 0);
ses_status_to_ctrl(map[elm_idx].elm_type,
&elmstat.cstat[0]);
cslot = (struct ses_ctrl_dev_slot*)&elmstat.cstat[0];
ses_ctrl_common_set_select(&cslot->common, 1);
ses_ctrl_dev_slot_set_rqst_ident(cslot, 0);
r = ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t)&elmstat);
ATF_REQUIRE_EQ(r, 0);
}
}
return(true);
}
ATF_TC_WITH_CLEANUP(setelmstat);
ATF_TC_HEAD(setelmstat, tc)
{
atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETELMSTAT");
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(setelmstat, tc)
{
if (!has_ses())
atf_tc_skip("No ses devices found");
for_one_ses_dev(do_setelmstat);
}
ATF_TC_CLEANUP(setelmstat, tc)
{
if (!has_ses())
return;
for_one_ses_dev(do_setelmstat_cleanup);
}
static bool
do_setencstat(const char *devname __unused, int fd)
{
unsigned char encstat;
int r, i;
bool worked = false;
encstat = 1 << SES_CTRL_PAGE_CRIT_SHIFT;
r = ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
ATF_REQUIRE_EQ(r, 0);
for (i = 0; i < 10; i++) {
r = ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &encstat);
ATF_REQUIRE_EQ(r, 0);
if (encstat & SES_CTRL_PAGE_CRIT_MASK) {
worked = true;
break;
}
usleep(100000);
}
if (!worked) {
return (false);
} else
return (true);
}
static bool
do_setencstat_cleanup(const char *devname __unused, int fd)
{
unsigned char encstat;
encstat = 0;
ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &encstat);
return (true);
}
ATF_TC_WITH_CLEANUP(setencstat);
ATF_TC_HEAD(setencstat, tc)
{
atf_tc_set_md_var(tc, "descr", "Exercise ENCIOC_SETENCSTAT");
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(setencstat, tc)
{
if (!has_ses())
atf_tc_skip("No ses devices found");
for_each_ses_dev(do_setencstat, O_RDWR);
}
ATF_TC_CLEANUP(setencstat, tc)
{
for_each_ses_dev(do_setencstat_cleanup, O_RDWR);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, setelmstat);
ATF_TP_ADD_TC(tp, setencstat);
return (atf_no_error());
}