diff -purN sg3_utils-1.19.orig/Makefile sg3_utils-1.19/Makefile
--- sg3_utils-1.19.orig/Makefile	2006-01-04 14:00:13.000000000 +0100
+++ sg3_utils-1.19/Makefile	2006-04-04 16:05:30.000000000 +0200
@@ -10,12 +10,12 @@ CC = gcc
 LD = gcc
 
 EXECS = sg_dd sgp_dd sgm_dd sg_read sg_map sg_scan sg_rbuf \
-  	sginfo sg_readcap sg_turs sg_inq sg_test_rwbuf \
- 	sg_start sg_reset sg_modes sg_logs sg_senddiag sg_opcodes \
- 	sg_persist sg_write_long sg_read_long sg_requests sg_ses \
+	sginfo sg_readcap sg_turs sg_inq sg_test_rwbuf \
+	sg_start sg_reset sg_modes sg_logs sg_senddiag sg_opcodes \
+	sg_persist sg_write_long sg_read_long sg_requests sg_ses \
 	sg_verify sg_emc_trespass sg_luns sg_sync sg_prevent \
 	sg_get_config sg_wr_mode sg_rtpg sg_reassign sg_format \
-	sg_rmsn sg_ident sg_map26
+	sg_rmsn sg_ident sg_map26 sg_rdac
 
 MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_read.8 sg_map.8 sg_scan.8 sg_rbuf.8 \
 	sginfo.8 sg_readcap.8 sg_turs.8 sg_inq.8 sg_test_rwbuf.8 \
@@ -24,7 +24,7 @@ MAN_PGS = sg_dd.8 sgp_dd.8 sgm_dd.8 sg_r
 	sg_requests.8 sg_ses.8 sg_verify.8 sg_emc_trespass.8 \
 	sg_luns.8 sg_sync.8 sg_prevent.8 sg_get_config.8 sg_wr_mode.8 \
 	sg_rtpg.8 sg_reassign.8 sg_format.8 sg_rmsn.8 sg_ident.8 \
-	sg_map26.8
+	sg_map26.8 sg_rdac.8
 MAN_PREF = man8
 
 HEADERS = sg_lib.h sg_cmds.h sg_pt.h
@@ -190,6 +190,10 @@ sg_ident: sg_ident.o libsgutils.la
 sg_map26: sg_map26.o
 	libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
 
+sg_rdac: sg_rdac.o libsgutils.la
+	libtool --mode=link $(LD) -o $@ $(LDFLAGS) $^
+
+
 install: $(EXECS)
 	install -d $(INSTDIR)
 	install -d $(LIBDIR)
diff -purN sg3_utils-1.19.orig/sg_inq.c sg3_utils-1.19/sg_inq.c
--- sg3_utils-1.19.orig/sg_inq.c	2006-01-24 13:41:47.000000000 +0100
+++ sg3_utils-1.19/sg_inq.c	2006-04-03 12:57:44.000000000 +0200
@@ -80,6 +80,8 @@ static char * version_str = "0.57 200501
 #define ATA_INFO_VPD  0x89
 #define BLOCK_LIMITS_VPD  0xb0
 #define UPR_EMC_VPD  0xc0
+#define RDAC_VERS_VPD 0xc2
+#define RDAC_VAC_VPD 0xc9
 
 #define DEF_ALLOC_LEN 252
 #define SAFE_STD_INQ_RESP_LEN 36
@@ -181,8 +183,9 @@ static struct vpd_name vpd_name_arr[] = 
     {0xb1, 0x11, "Security token (osd)"},
     {0xc0, 0, "vendor: Firmware numbers (seagate); Unit path report (EMC)"},
     {0xc1, 0, "vendor: Date code (seagate)"},
-    {0xc2, 0, "vendor: Jumper settings (seagate)"},
+    {0xc2, 0, "vendor: Jumper settings (seagate); Software version (RDAC)"},
     {0xc3, 0, "vendor: Device behavior (seagate)"},
+    {0xc9, 0, "Volume Access Control (RDAC)"},
 };
 
 const char * get_vpd_page_str(int vpd_page_num, int scsi_ptype)
@@ -982,6 +985,83 @@ static void decode_upr_vpd_c0_emc(unsign
     return;
 }
 
+static void decode_rdac_vpd_c2(unsigned char * buff, int len)
+{
+    if (len < 3) {
+        fprintf(stderr, "Software Version VPD page length too "
+                "short=%d\n", len);
+        return;
+    }
+    if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') {
+        fprintf(stderr, "Invalid page identifier %c%c%c%c, decoding "
+                "possible.\n" , buff[4], buff[5], buff[6], buff[7]);
+        return;
+    }
+    printf("  Software Version: %d.%d.%d\n", buff[8], buff[9], buff[10]);
+    printf("  Software Date: %02x/%02x/%02x\n", buff[11], buff[12], buff[13]);
+    printf("  Features:");
+    if (buff[14] & 0x01)
+	printf(" Dual Active,");
+    if (buff[14] & 0x02)
+	printf(" Series 3,");
+    if (buff[14] & 0x04)
+	printf(" Multiple Sub-enclosures,");
+    if (buff[14] & 0x08)
+	printf(" DCE/DRM,");
+    if (buff[14] & 0x10)
+	printf(" AVT,");
+    printf("\n");
+    printf("  Max. #of LUNS: %d\n", buff[15]);
+    return;
+}
+
+static void decode_rdac_vpd_c9(unsigned char * buff, int len)
+{
+    if (len < 3) {
+        fprintf(stderr, "Volume Access Control VPD page length too "
+                "short=%d\n", len);
+        return;
+    }
+    if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') {
+        fprintf(stderr, "Invalid page identifier %c%c%c%c, decoding "
+                "possible.\n" , buff[4], buff[5], buff[6], buff[7]);
+        return;
+    }
+    if (buff[7] != '1') {
+	fprintf(stderr, "Invalid page version '%c' (should be 1)\n",
+		buff[7]);
+    }
+    printf("  AVT:");
+    if (buff[8] & 0x80) {
+	printf(" Enabled");
+	if (buff[8] & 0x40)
+	    printf(" (Allow reads on sector 0)");
+	printf("\n");
+    } else {
+	printf(" Disabled\n");
+    }
+    printf("  Volume Access via: ");
+    if (buff[8] & 0x01)
+	printf("primary controller\n");
+    else
+	printf("alternate controller\n");
+
+    printf("  Path priority: %d ", buff[9] & 0xf);
+    switch(buff[9] & 0xf) {
+	case 0x1:
+	    printf("(preferred path)\n");
+	    break;
+	case 0x2:
+	    printf("(secondary path)\n");
+	    break;
+	default:
+	    printf("(unknown)\n");
+	    break;
+    }
+
+    return;
+}
+
 /* Returns 0 if Unit Serial Number VPD page contents found, else -1 */
 static int fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len,
                                  int verbose)
@@ -1642,6 +1722,64 @@ static int decode_vpd(int sg_fd, int num
             return 0;
         }
         break;
+    case RDAC_VERS_VPD:
+        if (!do_raw)
+            printf("VPD INQUIRY: Software Version (RDAC)\n");
+        if (0 == sg_ll_inquiry(sg_fd, 0, 1, RDAC_VERS_VPD, rsp_buff,
+                               DEF_ALLOC_LEN, 1, verbose)) {
+            len = rsp_buff[3] + 3;
+            if (RDAC_VERS_VPD != rsp_buff[1]) {
+                fprintf(stderr, "invalid VPD response; probably not "
+                        "supported\n");
+                return 1;
+            }
+            if (len > MX_ALLOC_LEN) {
+                fprintf(stderr, "response length too long: %d > %d\n", len,
+                       MX_ALLOC_LEN);
+                return 1;
+            } else if (len > DEF_ALLOC_LEN) {
+                if (sg_ll_inquiry(sg_fd, 0, 1, RDAC_VERS_VPD, rsp_buff, len, 1,
+                           verbose))
+                    return 1;
+            }
+            if (do_raw)
+                dStrRaw((const char *)rsp_buff, len);
+            else if (do_hex)
+                dStrHex((const char *)rsp_buff, len, 1);
+            else
+                decode_rdac_vpd_c2(rsp_buff, len);
+            return 0;
+        }
+        break;
+    case RDAC_VAC_VPD:
+        if (!do_raw)
+            printf("VPD INQUIRY: Volume Access Control (RDAC)\n");
+        if (0 == sg_ll_inquiry(sg_fd, 0, 1, RDAC_VAC_VPD, rsp_buff,
+                               DEF_ALLOC_LEN, 1, verbose)) {
+            len = rsp_buff[3] + 3;
+            if (RDAC_VAC_VPD != rsp_buff[1]) {
+                fprintf(stderr, "invalid VPD response; probably not "
+                        "supported\n");
+                return 1;
+            }
+            if (len > MX_ALLOC_LEN) {
+                fprintf(stderr, "response length too long: %d > %d\n", len,
+                       MX_ALLOC_LEN);
+                return 1;
+            } else if (len > DEF_ALLOC_LEN) {
+                if (sg_ll_inquiry(sg_fd, 0, 1, RDAC_VAC_VPD, rsp_buff, len, 1,
+                           verbose))
+                    return 1;
+            }
+            if (do_raw)
+                dStrRaw((const char *)rsp_buff, len);
+            else if (do_hex)
+                dStrHex((const char *)rsp_buff, len, 1);
+            else
+                decode_rdac_vpd_c9(rsp_buff, len);
+            return 0;
+        }
+        break;
     case SCSI_PORTS_VPD:
         if (!do_raw)
             printf("VPD INQUIRY: SCSI Ports page\n");
diff -purN sg3_utils-1.19.orig/sg_rdac.8 sg3_utils-1.19/sg_rdac.8
--- sg3_utils-1.19.orig/sg_rdac.8	1970-01-01 01:00:00.000000000 +0100
+++ sg3_utils-1.19/sg_rdac.8	2006-04-04 15:42:52.000000000 +0200
@@ -0,0 +1,33 @@
+.TH SG_RDAC "4" "Apr 2006" "sg3_utils-1.09" SG3_UTILS
+.SH NAME
+sg_rdac \- Display or Modify RDAC Redundant Controller Page
+.SH SYNOPSIS
+.B sg_rdac
+[\fI-a\fR] [\fI-f=<lun>\fR] [\fI-v\fR] \fI<sg_device>\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+sg_rdac displays or modifies the RDAC controller settings via the
+Redundant Controller Page (0x2C). When modifying the settings it
+allows to transfer the ownership of individual drives to the
+controller the command was received on.
+.TP
+-a
+Transfer all (visible) devices
+.TP
+-f=<lun>
+Transfer the device with LUN <lun>. This command will only work if
+the controller supports 'Dual Active Mode' (aka active/active mode).
+.TP
+.TP
+-v
+be verbose
+.SH AUTHOR
+Written by Hannes Reinecke <hare at suse dot com>, based on sg_emc_trespass.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2006 Hannes Reinecke, Douglas Gilbert.
+.br
+This software is distributed under the GPL version 2. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff -purN sg3_utils-1.19.orig/sg_rdac.c sg3_utils-1.19/sg_rdac.c
--- sg3_utils-1.19.orig/sg_rdac.c	1970-01-01 01:00:00.000000000 +0100
+++ sg3_utils-1.19/sg_rdac.c	2006-04-04 15:35:52.000000000 +0200
@@ -0,0 +1,363 @@
+/*
+ * sg_rdac
+ *
+ * Retrieve / set RDAC options.
+ *
+ * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
+ *
+ * Based on sg_modes.c and sg_emc_trespass.c; credits from there apply.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include "sg_lib.h"
+#include "sg_cmds.h"
+#include "sg_io_linux.h"
+
+unsigned char mode6_hdr[] = {
+    75, /* Length */
+    0, /* medium */
+    0, /* params */
+    8, /* Block descriptor length */
+};
+
+unsigned char block_descriptor[] = {
+    0, /* Density code */
+    0, 0, 0, /* Number of blocks */
+    0, /* Reserved */
+    0, 0x02, 0, /* 512 byte blocks */
+};
+
+struct rdac_legacy_page {
+    unsigned char  page_code;
+    unsigned char  page_length;
+    char	   current_serial[16];
+    char	   alternate_serial[16];
+    unsigned char  current_mode_msb;
+    unsigned char  current_mode_lsb;
+    unsigned char  alternate_mode_msb;
+    unsigned char  alternate_mode_lsb;
+    unsigned char  quiescence;
+    unsigned char  options;
+    unsigned char  lun_table[32];
+    unsigned char  lun_table_exp[32];
+    unsigned short reserved;
+};
+
+static int do_verbose = 0;
+
+static void dump_mode_page( unsigned char *page, int len )
+{
+	int i, k;
+
+	for (k = 0; k < len; k += 16) {
+
+		printf("%x:",k / 16);
+		for (i = 0; i < 16; i++) {
+			printf(" %02x", page[k + i]);
+			if (k + i >= len) {
+				printf("\n");
+				break;
+			}
+		}
+		printf("\n");
+	}
+
+}
+
+#define MX_ALLOC_LEN (1024 * 4)
+#define RDAC_CONTROLLER_PAGE 0x2c
+#define RDAC_CONTROLLER_PAGE_LEN 0x68
+#define LEGACY_PAGE 0x00
+#define EXPANDED_LUN_SPACE_PAGE 0x01
+#define RDAC_FAIL_ALL_PATHS 0x1
+#define RDAC_FAIL_SELECTED_PATHS 0x2
+#define RDAC_FORCE_QUIESCENCE 0x2
+#define RDAC_QUIESCENCE_TIME 10
+
+static int fail_all_paths(int fd)
+{
+	unsigned char fail_paths_pg[118];
+	struct rdac_legacy_page *rdac_page;
+	int res;
+
+	memset(fail_paths_pg, 0, 118);
+	memcpy(fail_paths_pg, mode6_hdr, 4);
+	memcpy(fail_paths_pg + 4, block_descriptor, 8);
+	rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
+	rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40;
+	rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
+	rdac_page->quiescence = RDAC_QUIESCENCE_TIME;
+	rdac_page->options = RDAC_FORCE_QUIESCENCE;
+	rdac_page->current_mode_lsb = RDAC_FAIL_ALL_PATHS;
+	
+	res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
+                                 fail_paths_pg, 118,
+                                 1, (do_verbose ? 2 : 0));
+
+        switch (res) {
+        case 0:
+                if (do_verbose)
+                        fprintf(stderr, "fail paths successful\n");
+                break;
+        case SG_LIB_CAT_INVALID_OP:
+                fprintf(stderr, "fail paths page failed (Invalid opcode)\n");
+		break;
+        case SG_LIB_CAT_ILLEGAL_REQ:
+                fprintf(stderr, "fail paths page failed (illegal request)\n");
+                break;
+        default:
+                if (do_verbose)
+                        fprintf(stderr, "fail paths failed\n");
+                break;
+        }
+
+	return res;
+}
+
+static int fail_this_path(int fd, int lun)
+{
+	unsigned char fail_paths_pg[118];
+	struct rdac_legacy_page *rdac_page;
+	int res;
+
+	memset(fail_paths_pg, 0, 118);
+	memcpy(fail_paths_pg, mode6_hdr, 4);
+	memcpy(fail_paths_pg + 4, block_descriptor, 8);
+	rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8);
+	rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40;
+	rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN;
+	rdac_page->current_mode_lsb =  RDAC_FAIL_SELECTED_PATHS;
+	rdac_page->quiescence = RDAC_QUIESCENCE_TIME;
+	rdac_page->options = RDAC_FORCE_QUIESCENCE;
+	memset(rdac_page->lun_table, 0x0, 32);
+	rdac_page->lun_table[lun] = 0x81;
+
+	res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */,
+                                 fail_paths_pg, 118,
+                                 1, (do_verbose ? 2 : 0));
+
+        switch (res) {
+        case 0:
+                if (do_verbose)
+                        fprintf(stderr, "fail paths successful\n");
+                break;
+        case SG_LIB_CAT_INVALID_OP:
+                fprintf(stderr, "fail paths page failed (Invalid opcode)\n");
+		break;
+        case SG_LIB_CAT_ILLEGAL_REQ:
+                fprintf(stderr, "fail lun %d page failed (illegal request)\n",
+			lun);
+                break;
+        default:
+                if (do_verbose)
+                        fprintf(stderr, "fail paths failed\n");
+                break;
+        }
+
+	return res;
+}
+
+static void print_rdac_mode( unsigned char *ptr )
+{
+	struct rdac_legacy_page *rdac_ptr;
+	int i, k, bd_len;
+
+	bd_len = ptr[3];
+
+	rdac_ptr = (struct rdac_legacy_page *)(ptr + 4 + bd_len);
+
+	printf("RDAC Legacy page\n");
+	printf("  Controller serial: %s\n",
+	       rdac_ptr->current_serial);
+	printf("  Alternate controller serial: %s\n",
+	       rdac_ptr->alternate_serial);
+	printf("  RDAC mode (redundant processor): ");
+	switch (rdac_ptr->current_mode_msb) {
+	case 0x00:
+		printf("alternate controller not present; ");
+		break;
+	case 0x01:
+		printf("alternate controller present; ");
+		break;
+	default:
+		printf("(Unknown controller status 0x%x); ",
+		       rdac_ptr->current_mode_msb);
+		break;
+	}
+	switch (rdac_ptr->current_mode_lsb) {
+	case 0x0:
+		printf("inactive\n");
+		break;
+	case 0x1:
+		printf("active\n");
+		break;
+	case 0x2:
+		printf("Dual active mode\n");
+		break;
+	default:
+		printf("(Unknown mode 0x%x)\n",
+		       rdac_ptr->current_mode_lsb);
+	}
+
+	printf("  RDAC mode (alternate processor): ");
+	switch (rdac_ptr->alternate_mode_msb) {
+	case 0x00:
+		printf("alternate controller not present; ");
+		break;
+	case 0x01:
+		printf("alternate controller present; ");
+		break;
+	case 0x02:
+		printf("active/active mode; ");
+		break;
+	default:
+		printf("(Unknown status 0x%x); ", 
+		       rdac_ptr->alternate_mode_msb);
+		break;
+	}
+	switch (rdac_ptr->alternate_mode_lsb) {
+	case 0x0:
+		printf("inactive\n");
+		break;
+	case 0x1:
+		printf("active\n");
+		break;
+	case 0x2:
+		printf("Dual active mode\n");
+		break;
+	case 0x04:
+		printf("held in reset\n");
+		break;
+	default:
+		printf("(Unknown mode 0x%x)\n",
+		       rdac_ptr->alternate_mode_lsb);
+	}
+	printf("  Quiescence timeout: %d\n", rdac_ptr->quiescence);
+	printf("  RDAC option 0x%x\n", rdac_ptr->options);
+	printf ("  LUN Table:\n");
+	for (k = 0; k < 32; k += 8) {
+		printf("    %x:",k / 8);
+		for (i = 0; i < 8; i++) {
+			switch (rdac_ptr->lun_table[k + i]) {
+			case 0x0:
+				printf(" x");
+				break;
+			case 0x1:
+				printf(" p");
+				break;
+			case 0x2:
+				printf(" a");
+				break;
+			case 0x3:
+				printf(" u");
+				break;
+			default:
+				printf(" ?");
+				break;
+			}
+		}
+		printf("\n");
+	}
+}
+
+static void usage()
+{
+    printf("Usage:  sg_rdac [-a] [-f=<lun>] [-v] <scsi_device>\n"
+           " where -a       transfer all devices to the controller\n"
+           "                serving <scsi_device>.\n"
+           "       -f=<lun> transfer the device with LUN <lun> to the\n"
+           "                controller serving <scsi_device>\n"
+           "       -v       verbose\n"
+	   " Display/Modify RDAC Redundant Controller Page 0x2c.\n"
+           " If [-a] or [-f] is not specified the current settings"
+           " are displayed.\n");
+}
+
+int main(int argc, char * argv[])
+{
+	unsigned char rsp_buff[MX_ALLOC_LEN];
+        char **argptr;
+        char * file_name = 0;
+        int res, fd, k, lun = -1;
+	int fail_all = 0;
+	int fail_path = 0;
+        
+        if (argc < 2) 
+                usage ();
+
+        for (k = 1; k < argc; ++k) {
+                argptr = argv + k;
+                if (!strcmp (*argptr, "-v"))
+                        ++do_verbose;
+		else if (!strncmp(*argptr, "-f=",3)) {
+			++fail_path;
+			lun = strtoul(*argptr + 3, NULL, 0);
+		}
+		else if (!strcmp(*argptr, "-a")) {
+			++fail_all;
+		}
+                else if (*argv[k] == '-') {
+                        fprintf(stderr, "Unrecognized switch: %s\n", argv[k]);
+                        file_name = 0;
+                        break;
+                }
+                else if (0 == file_name)
+                        file_name = argv[k];
+                else {
+                        fprintf(stderr, "too many arguments\n");
+                        file_name = 0;
+                        break;
+                }
+        }
+        if (0 == file_name) {
+                usage();
+                return 1;
+        }
+                
+        fd = open(file_name, O_RDWR | O_NONBLOCK);
+        if (fd < 0) {
+                fprintf(stderr, "Error trying to open %s\n", file_name);
+                perror("");
+                usage();
+                return 2;
+        }
+
+	if (do_verbose)
+		dump_mode_page(rsp_buff, rsp_buff[0]);
+
+	if (fail_all) {
+		res = fail_all_paths(fd);
+	} else if (fail_path) {
+		res = fail_this_path(fd, lun);
+	} else {
+		res = sg_ll_mode_sense6(fd, /*DBD*/ 0, /* page control */0, 
+					0x2c, 0, rsp_buff, 252, 
+					1, do_verbose);
+
+		if (!res)
+			print_rdac_mode(rsp_buff);
+	}
+	if (SG_LIB_CAT_INVALID_OP == res)
+		fprintf(stderr, ">>>>>> try again without the '-6' "
+			"switch for a 10 byte MODE SENSE command\n");
+	else if (SG_LIB_CAT_ILLEGAL_REQ == res)
+		fprintf(stderr, "invalid field in cdb (perhaps subpages "
+			"or page control (PC) not supported)\n");
+	else if (res)
+		fprintf(stderr," mode sense failed\n");
+
+        close (fd);
+        return res?1:0;
+}
