summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-12-05 07:23:25 +0000
committermav <mav@FreeBSD.org>2014-12-05 07:23:25 +0000
commitcc2f0f4af54e23d5cd1b038f9967f372ff24d709 (patch)
tree38decc11d9d460be33e6cdbc59d3ab073605d4f5 /sys/cam
parentebd3bcb8456e32e6cd035986c2caaf03e8a987b5 (diff)
downloadFreeBSD-src-cc2f0f4af54e23d5cd1b038f9967f372ff24d709.zip
FreeBSD-src-cc2f0f4af54e23d5cd1b038f9967f372ff24d709.tar.gz
MFC r274785: Partially reconstruct Active/Standby clusting.
In this mode one head is in Active state, supporting all commands, while another is in Standby state, supporting only minimal LUN discovery subset. It is still incomplete since Standby state requires reservation support, which is impossible to do right without having interlink between heads. But it allows to run some basic experiments.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ctl/ctl.c123
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c6
-rw-r--r--sys/cam/ctl/ctl_frontend.c4
-rw-r--r--sys/cam/ctl/ctl_frontend.h2
-rw-r--r--sys/cam/ctl/ctl_frontend_cam_sim.c2
-rw-r--r--sys/cam/ctl/ctl_frontend_internal.c4
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c2
-rw-r--r--sys/cam/ctl/ctl_ha.h3
-rw-r--r--sys/cam/ctl/ctl_private.h6
-rw-r--r--sys/cam/ctl/ctl_tpc_local.c3
-rw-r--r--sys/cam/ctl/scsi_ctl.c2
11 files changed, 99 insertions, 58 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 9b1c74c..e0d9cc1 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -357,7 +357,6 @@ static struct ctl_logical_block_provisioning_page lbp_page_changeable = {{
static int rcv_sync_msg;
static int persis_offset;
static uint8_t ctl_pause_rtr;
-static int ctl_is_single = 1;
SYSCTL_NODE(_kern_cam, OID_AUTO, ctl, CTLFLAG_RD, 0, "CAM Target Layer");
static int worker_threads = -1;
@@ -972,12 +971,42 @@ ctl_copy_sense_data(union ctl_ha_msg *src, union ctl_io *dest)
}
static int
+ctl_ha_state_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct ctl_softc *softc = (struct ctl_softc *)arg1;
+ struct ctl_lun *lun;
+ int error, value, i;
+
+ if (softc->flags & CTL_FLAG_ACTIVE_SHELF)
+ value = 0;
+ else
+ value = 1;
+
+ error = sysctl_handle_int(oidp, &value, 0, req);
+ if ((error != 0) || (req->newptr == NULL))
+ return (error);
+
+ mtx_lock(&softc->ctl_lock);
+ if (value == 0)
+ softc->flags |= CTL_FLAG_ACTIVE_SHELF;
+ else
+ softc->flags &= ~CTL_FLAG_ACTIVE_SHELF;
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ mtx_lock(&lun->lun_lock);
+ for (i = 0; i < CTL_MAX_INITIATORS; i++)
+ lun->pending_ua[i] |= CTL_UA_ASYM_ACC_CHANGE;
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
+ return (0);
+}
+
+static int
ctl_init(void)
{
struct ctl_softc *softc;
struct ctl_io_pool *internal_pool, *emergency_pool, *other_pool;
struct ctl_port *port;
- uint8_t sc_id =0;
int i, error, retval;
//int isc_retval;
@@ -1035,16 +1064,17 @@ ctl_init(void)
* In Copan's HA scheme, the "master" and "slave" roles are
* figured out through the slot the controller is in. Although it
* is an active/active system, someone has to be in charge.
- */
-#ifdef NEEDTOPORT
- scmicro_rw(SCMICRO_GET_SHELF_ID, &sc_id);
-#endif
-
- if (sc_id == 0) {
- softc->flags |= CTL_FLAG_MASTER_SHELF;
- persis_offset = 0;
+ */
+ SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree),
+ OID_AUTO, "ha_id", CTLFLAG_RDTUN, &softc->ha_id, 0,
+ "HA head ID (0 - no HA)");
+ if (softc->ha_id == 0) {
+ softc->flags |= CTL_FLAG_ACTIVE_SHELF;
+ softc->is_single = 1;
+ softc->port_offset = 0;
} else
- persis_offset = CTL_MAX_INITIATORS;
+ softc->port_offset = (softc->ha_id - 1) * CTL_MAX_PORTS;
+ persis_offset = softc->port_offset * CTL_MAX_INIT_PER_PORT;
/*
* XXX KDM need to figure out where we want to get our target ID
@@ -1157,12 +1187,15 @@ ctl_init(void)
port->max_targets = 15;
port->max_target_id = 15;
- if (ctl_port_register(&softc->ioctl_info.port,
- (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0) {
+ if (ctl_port_register(&softc->ioctl_info.port) != 0) {
printf("ctl: ioctl front end registration failed, will "
"continue anyway\n");
}
+ SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree),
+ OID_AUTO, "ha_state", CTLTYPE_INT | CTLFLAG_RWTUN,
+ softc, 0, ctl_ha_state_sysctl, "I", "HA state for this head");
+
#ifdef CTL_IO_DELAY
if (sizeof(struct callout) > CTL_TIMER_BYTES) {
printf("sizeof(struct callout) %zd > CTL_TIMER_BYTES %zd\n",
@@ -1264,10 +1297,10 @@ ctl_close(struct cdev *dev, int flags, int fmt, struct thread *td)
int
ctl_port_enable(ctl_port_type port_type)
{
- struct ctl_softc *softc;
+ struct ctl_softc *softc = control_softc;
struct ctl_port *port;
- if (ctl_is_single == 0) {
+ if (softc->is_single == 0) {
union ctl_ha_msg msg_info;
int isc_retval;
@@ -1292,8 +1325,6 @@ ctl_port_enable(ctl_port_type port_type)
#endif
}
- softc = control_softc;
-
STAILQ_FOREACH(port, &softc->port_list, links) {
if (port_type & port->port_type)
{
@@ -7439,8 +7470,8 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio)
{
struct scsi_maintenance_in *cdb;
int retval;
- int alloc_len, ext, total_len = 0, g, p, pc, pg;
- int num_target_port_groups, num_target_ports, single;
+ int alloc_len, ext, total_len = 0, g, p, pc, pg, gs, os;
+ int num_target_port_groups, num_target_ports;
struct ctl_lun *lun;
struct ctl_softc *softc;
struct ctl_port *port;
@@ -7474,8 +7505,7 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio)
return(retval);
}
- single = ctl_is_single;
- if (single)
+ if (softc->is_single)
num_target_port_groups = 1;
else
num_target_port_groups = NUM_TARGET_PORT_GROUPS;
@@ -7531,18 +7561,26 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio)
tpg_desc = &rtg_ptr->groups[0];
}
- pg = ctsio->io_hdr.nexus.targ_port / CTL_MAX_PORTS;
mtx_lock(&softc->ctl_lock);
+ pg = softc->port_offset / CTL_MAX_PORTS;
+ if (softc->flags & CTL_FLAG_ACTIVE_SHELF) {
+ if (softc->ha_mode == CTL_HA_MODE_ACT_STBY) {
+ gs = TPG_ASYMMETRIC_ACCESS_OPTIMIZED;
+ os = TPG_ASYMMETRIC_ACCESS_STANDBY;
+ } else if (lun->flags & CTL_LUN_PRIMARY_SC) {
+ gs = TPG_ASYMMETRIC_ACCESS_OPTIMIZED;
+ os = TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED;
+ } else {
+ gs = TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED;
+ os = TPG_ASYMMETRIC_ACCESS_OPTIMIZED;
+ }
+ } else {
+ gs = TPG_ASYMMETRIC_ACCESS_STANDBY;
+ os = TPG_ASYMMETRIC_ACCESS_OPTIMIZED;
+ }
for (g = 0; g < num_target_port_groups; g++) {
- if (g == pg)
- tpg_desc->pref_state = TPG_PRIMARY |
- TPG_ASYMMETRIC_ACCESS_OPTIMIZED;
- else
- tpg_desc->pref_state =
- TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED;
- tpg_desc->support = TPG_AO_SUP;
- if (!single)
- tpg_desc->support |= TPG_AN_SUP;
+ tpg_desc->pref_state = (g == pg) ? gs : os;
+ tpg_desc->support = TPG_AO_SUP | TPG_AN_SUP | TPG_S_SUP;
scsi_ulto2b(g + 1, tpg_desc->target_port_group);
tpg_desc->status = TPG_IMPLICIT;
pc = 0;
@@ -10181,12 +10219,11 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
struct ctl_lun *lun;
struct ctl_port *port;
int data_len, num_target_ports, iid_len, id_len, g, pg, p;
- int num_target_port_groups, single;
+ int num_target_port_groups;
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
- single = ctl_is_single;
- if (single)
+ if (softc->is_single)
num_target_port_groups = 1;
else
num_target_port_groups = NUM_TARGET_PORT_GROUPS;
@@ -10246,10 +10283,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
pd = &sp->design[0];
mtx_lock(&softc->ctl_lock);
- if (softc->flags & CTL_FLAG_MASTER_SHELF)
- pg = 0;
- else
- pg = 1;
+ pg = softc->port_offset / CTL_MAX_PORTS;
for (g = 0; g < num_target_port_groups; g++) {
STAILQ_FOREACH(port, &softc->port_list, links) {
if ((port->status & CTL_PORT_STATUS_ONLINE) == 0)
@@ -11329,15 +11363,12 @@ ctl_scsiio_lun_check(struct ctl_softc *ctl_softc, struct ctl_lun *lun,
* If this shelf is a secondary shelf controller, we have to reject
* any media access commands.
*/
-#if 0
- /* No longer needed for HA */
- if (((ctl_softc->flags & CTL_FLAG_MASTER_SHELF) == 0)
- && ((entry->flags & CTL_CMD_FLAG_OK_ON_SECONDARY) == 0)) {
+ if ((ctl_softc->flags & CTL_FLAG_ACTIVE_SHELF) == 0 &&
+ (entry->flags & CTL_CMD_FLAG_OK_ON_SECONDARY) == 0) {
ctl_set_lun_standby(ctsio);
retval = 1;
goto bailout;
}
-#endif
if (entry->pattern & CTL_LUN_PAT_WRITE) {
if (lun->flags & CTL_LUN_READONLY) {
@@ -14392,7 +14423,7 @@ ctl_isc_start(struct ctl_ha_component *c, ctl_ha_state state)
// UNKNOWN->HA or UNKNOWN->SINGLE (bootstrap)
if (c->state == CTL_HA_STATE_UNKNOWN ) {
- ctl_is_single = 0;
+ control_softc->is_single = 0;
if (ctl_ha_msg_create(CTL_HA_CHAN_CTL, ctl_isc_event_handler)
!= CTL_HA_STATUS_SUCCESS) {
printf("ctl_isc_start: ctl_ha_msg_create failed.\n");
@@ -14402,14 +14433,14 @@ ctl_isc_start(struct ctl_ha_component *c, ctl_ha_state state)
&& CTL_HA_STATE_IS_SINGLE(state)){
// HA->SINGLE transition
ctl_failover();
- ctl_is_single = 1;
+ control_softc->is_single = 1;
} else {
printf("ctl_isc_start:Invalid state transition %X->%X\n",
c->state, state);
ret = CTL_HA_COMP_STATUS_ERROR;
}
if (CTL_HA_STATE_IS_SINGLE(state))
- ctl_is_single = 1;
+ control_softc->is_single = 1;
c->state = state;
c->status = ret;
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index fedc110..5ae5057 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -800,12 +800,18 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
/* 3B WRITE BUFFER */
{ctl_write_buffer, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_CMD_FLAG_OK_ON_STOPPED |
+ CTL_CMD_FLAG_OK_ON_INOPERABLE |
+ CTL_CMD_FLAG_OK_ON_OFFLINE |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE,
10, {0x1f, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}},
/* 3C READ BUFFER */
{ctl_read_buffer, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_CMD_FLAG_OK_ON_STOPPED |
+ CTL_CMD_FLAG_OK_ON_INOPERABLE |
+ CTL_CMD_FLAG_OK_ON_OFFLINE |
CTL_FLAG_DATA_IN |
CTL_CMD_FLAG_ALLOW_ON_PR_WRESV,
CTL_LUN_PAT_NONE,
diff --git a/sys/cam/ctl/ctl_frontend.c b/sys/cam/ctl/ctl_frontend.c
index 8a992cc..7047093 100644
--- a/sys/cam/ctl/ctl_frontend.c
+++ b/sys/cam/ctl/ctl_frontend.c
@@ -136,7 +136,7 @@ ctl_frontend_find(char *frontend_name)
}
int
-ctl_port_register(struct ctl_port *port, int master_shelf)
+ctl_port_register(struct ctl_port *port)
{
struct ctl_io_pool *pool;
int port_num;
@@ -193,7 +193,7 @@ error:
STAILQ_INIT(&port->options);
mtx_lock(&control_softc->ctl_lock);
- port->targ_port = port_num + (master_shelf != 0 ? 0 : CTL_MAX_PORTS);
+ port->targ_port = port_num + control_softc->port_offset;
STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links);
STAILQ_INSERT_TAIL(&control_softc->port_list, port, links);
control_softc->ctl_ports[port_num] = port;
diff --git a/sys/cam/ctl/ctl_frontend.h b/sys/cam/ctl/ctl_frontend.h
index 825ff50..06ae5a1 100644
--- a/sys/cam/ctl/ctl_frontend.h
+++ b/sys/cam/ctl/ctl_frontend.h
@@ -278,7 +278,7 @@ struct ctl_frontend * ctl_frontend_find(char *frontend_name);
* This may block until resources are allocated. Called at FETD module load
* time. Returns 0 for success, non-zero for failure.
*/
-int ctl_port_register(struct ctl_port *port, int master_SC);
+int ctl_port_register(struct ctl_port *port);
/*
* Called at FETD module unload time.
diff --git a/sys/cam/ctl/ctl_frontend_cam_sim.c b/sys/cam/ctl/ctl_frontend_cam_sim.c
index 7cdd5b7..93c12f4 100644
--- a/sys/cam/ctl/ctl_frontend_cam_sim.c
+++ b/sys/cam/ctl/ctl_frontend_cam_sim.c
@@ -164,7 +164,7 @@ cfcs_init(void)
port->max_targets = 1;
port->max_target_id = 15;
- retval = ctl_port_register(port, /*master_SC*/ 1);
+ retval = ctl_port_register(port);
if (retval != 0) {
printf("%s: ctl_port_register() failed with error %d!\n",
__func__, retval);
diff --git a/sys/cam/ctl/ctl_frontend_internal.c b/sys/cam/ctl/ctl_frontend_internal.c
index ac972f3..1d74737 100644
--- a/sys/cam/ctl/ctl_frontend_internal.c
+++ b/sys/cam/ctl/ctl_frontend_internal.c
@@ -244,8 +244,6 @@ cfi_init(void)
memset(softc, 0, sizeof(*softc));
mtx_init(&softc->lock, "CTL frontend mutex", NULL, MTX_DEF);
- softc->flags |= CTL_FLAG_MASTER_SHELF;
-
STAILQ_INIT(&softc->lun_list);
STAILQ_INIT(&softc->metatask_list);
sprintf(softc->fe_name, "kernel");
@@ -264,7 +262,7 @@ cfi_init(void)
port->max_targets = 15;
port->max_target_id = 15;
- if (ctl_port_register(port, (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0)
+ if (ctl_port_register(port) != 0)
{
printf("%s: internal frontend registration failed\n", __func__);
return (0);
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 4182717..ef944e2 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -2054,7 +2054,7 @@ cfiscsi_ioctl_port_create(struct ctl_req *req)
desc->length = idlen;
strlcpy(desc->identifier, target, idlen);
- retval = ctl_port_register(port, /*master_SC*/ 1);
+ retval = ctl_port_register(port);
if (retval != 0) {
ctl_free_opts(&port->options);
cfiscsi_target_release(ct);
diff --git a/sys/cam/ctl/ctl_ha.h b/sys/cam/ctl/ctl_ha.h
index 6293c7c..0c004b3 100644
--- a/sys/cam/ctl/ctl_ha.h
+++ b/sys/cam/ctl/ctl_ha.h
@@ -38,6 +38,8 @@
/*
* CTL High Availability Modes:
*
+ * CTL_HA_MODE_ACT_STBY: One side is in Active state and processing commands,
+ * the other side is in Standby state, returning errors.
* CTL_HA_MODE_SER_ONLY: Commands are serialized to the other side. Write
* mirroring and read re-direction are assumed to
* happen in the back end.
@@ -46,6 +48,7 @@
*/
typedef enum {
+ CTL_HA_MODE_ACT_STBY,
CTL_HA_MODE_SER_ONLY,
CTL_HA_MODE_XFER
} ctl_ha_mode;
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index 7b66c7f..e3ebe7a 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -442,7 +442,7 @@ struct ctl_lun {
typedef enum {
CTL_FLAG_REAL_SYNC = 0x02,
- CTL_FLAG_MASTER_SHELF = 0x04
+ CTL_FLAG_ACTIVE_SHELF = 0x04
} ctl_gen_flags;
#define CTL_MAX_THREADS 16
@@ -467,6 +467,10 @@ struct ctl_softc {
int num_luns;
ctl_gen_flags flags;
ctl_ha_mode ha_mode;
+ int ha_id;
+ int ha_state;
+ int is_single;
+ int port_offset;
int inquiry_pq_no_lun;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
diff --git a/sys/cam/ctl/ctl_tpc_local.c b/sys/cam/ctl/ctl_tpc_local.c
index 8fb7978..97a5f98 100644
--- a/sys/cam/ctl/ctl_tpc_local.c
+++ b/sys/cam/ctl/ctl_tpc_local.c
@@ -87,7 +87,6 @@ CTL_FRONTEND_DECLARE(ctltpc, tpcl_frontend);
static int
tpcl_init(void)
{
- struct ctl_softc *softc = control_softc;
struct tpcl_softc *tsoftc = &tpcl_softc;
struct ctl_port *port;
struct scsi_transportid_spi *tid;
@@ -112,7 +111,7 @@ tpcl_init(void)
port->max_target_id = 0;
port->max_initiators = 1;
- if (ctl_port_register(port, (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0)
+ if (ctl_port_register(port) != 0)
{
printf("%s: tpc frontend registration failed\n", __func__);
return (0);
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c
index ff80f3e..cbdf36c 100644
--- a/sys/cam/ctl/scsi_ctl.c
+++ b/sys/cam/ctl/scsi_ctl.c
@@ -425,7 +425,7 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
printf("%s: calling ctl_port_register() for %s%d\n",
__func__, cpi->dev_name, cpi->unit_number);
#endif
- retval = ctl_port_register(port, /*master_SC*/ 1);
+ retval = ctl_port_register(port);
if (retval != 0) {
printf("%s: ctl_port_register() failed with "
"error %d!\n", __func__, retval);
OpenPOWER on IntegriCloud