Author: mav
Date: Wed Jul 16 15:57:17 2014
New Revision: 268767
URL: http://svnweb.freebsd.org/changeset/base/268767

Log:
  Add support for VMWare dialect of EXTENDED COPY command, aka VAAI Clone.
  
  This allows to clone VMs and move them between LUNs inside one storage
  host without generating extra network traffic to the initiator and back,
  and without being limited by network bandwidth.
  
  LUNs participating in copy operation should have UNIQUE NAA or EUI IDs set.
  For LUNs without these IDs VMWare will use traditional copy operations.
  
  Beware: the above LUN IDs explicitly set to values non-unique from the VM
  cluster point of view may cause data corruption if wrong LUN is addressed!
  
  MFC after:    2 weeks
  Sponsored by: iXsystems, Inc.

Added:
  head/sys/cam/ctl/ctl_tpc.c   (contents, props changed)
  head/sys/cam/ctl/ctl_tpc.h   (contents, props changed)
  head/sys/cam/ctl/ctl_tpc_local.c   (contents, props changed)
Modified:
  head/sys/cam/ctl/ctl.c
  head/sys/cam/ctl/ctl_cmd_table.c
  head/sys/cam/ctl/ctl_frontend.c
  head/sys/cam/ctl/ctl_frontend.h
  head/sys/cam/ctl/ctl_frontend_iscsi.c
  head/sys/cam/ctl/ctl_private.h
  head/sys/cam/ctl/ctl_ser_table.c
  head/sys/cam/ctl/scsi_ctl.c
  head/sys/cam/scsi/scsi_all.h
  head/sys/conf/files
  head/sys/modules/ctl/Makefile
  head/usr.sbin/ctladm/ctladm.8

Modified: head/sys/cam/ctl/ctl.c
==============================================================================
--- head/sys/cam/ctl/ctl.c      Wed Jul 16 14:08:01 2014        (r268766)
+++ head/sys/cam/ctl/ctl.c      Wed Jul 16 15:57:17 2014        (r268767)
@@ -320,10 +320,10 @@ SYSCTL_INT(_kern_cam_ctl, OID_AUTO, verb
 
 /*
  * Supported pages (0x00), Serial number (0x80), Device ID (0x83),
- * SCSI Ports (0x88), Block limits (0xB0) and
+ * SCSI Ports (0x88), Third-party Copy (0x8F), Block limits (0xB0) and
  * Logical Block Provisioning (0xB2)
  */
-#define SCSI_EVPD_NUM_SUPPORTED_PAGES  6
+#define SCSI_EVPD_NUM_SUPPORTED_PAGES  7
 
 static void ctl_isc_event_handler(ctl_ha_channel chanel, ctl_ha_event event,
                                  int param);
@@ -349,8 +349,6 @@ static int ctl_ioctl_fill_ooa(struct ctl
                              struct ctl_ooa_entry *kern_entries);
 static int ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
                     struct thread *td);
-uint32_t ctl_get_resindex(struct ctl_nexus *nexus);
-uint32_t ctl_port_idx(int port_num);
 static uint32_t ctl_map_lun(int port_num, uint32_t lun);
 static uint32_t ctl_map_lun_back(int port_num, uint32_t lun);
 #ifdef unused
@@ -4598,6 +4596,7 @@ ctl_alloc_lun(struct ctl_softc *ctl_soft
        TAILQ_INIT(&lun->ooa_queue);
        TAILQ_INIT(&lun->blocked_queue);
        STAILQ_INIT(&lun->error_list);
+       ctl_tpc_init(lun);
 
        /*
         * Initialize the mode page index.
@@ -4749,6 +4748,7 @@ ctl_free_lun(struct ctl_lun *lun)
        atomic_subtract_int(&lun->be_lun->be->num_luns, 1);
        lun->be_lun->lun_shutdown(lun->be_lun->be_lun);
 
+       ctl_tpc_shutdown(lun);
        mtx_destroy(&lun->lun_lock);
        free(lun->lun_devid, M_CTL);
        if (lun->flags & CTL_LUN_MALLOCED)
@@ -9821,10 +9821,12 @@ ctl_inquiry_evpd_supported(struct ctl_sc
        pages->page_list[2] = SVPD_DEVICE_ID;
        /* SCSI Ports */
        pages->page_list[3] = SVPD_SCSI_PORTS;
+       /* Third-party Copy */
+       pages->page_list[4] = SVPD_SCSI_TPC;
        /* Block limits */
-       pages->page_list[4] = SVPD_BLOCK_LIMITS;
+       pages->page_list[5] = SVPD_BLOCK_LIMITS;
        /* Logical Block Provisioning */
-       pages->page_list[5] = SVPD_LBP;
+       pages->page_list[6] = SVPD_LBP;
 
        ctsio->scsi_status = SCSI_STATUS_OK;
 
@@ -10023,7 +10025,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_s
        struct scsi_vpd_port_designation_cont *pdc;
        struct ctl_lun *lun;
        struct ctl_port *port;
-       int data_len, num_target_ports, id_len, g, pg, p;
+       int data_len, num_target_ports, iid_len, id_len, g, pg, p;
        int num_target_port_groups, single;
 
        lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
@@ -10034,6 +10036,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_s
        else
                num_target_port_groups = NUM_TARGET_PORT_GROUPS;
        num_target_ports = 0;
+       iid_len = 0;
        id_len = 0;
        mtx_lock(&softc->ctl_lock);
        STAILQ_FOREACH(port, &softc->port_list, links) {
@@ -10043,6 +10046,8 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_s
                    CTL_MAX_LUNS)
                        continue;
                num_target_ports++;
+               if (port->init_devid)
+                       iid_len += port->init_devid->len;
                if (port->port_devid)
                        id_len += port->port_devid->len;
        }
@@ -10050,7 +10055,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_s
 
        data_len = sizeof(struct scsi_vpd_scsi_ports) + num_target_port_groups *
            num_target_ports * (sizeof(struct scsi_vpd_port_designation) +
-            sizeof(struct scsi_vpd_port_designation_cont)) + id_len;
+            sizeof(struct scsi_vpd_port_designation_cont)) + iid_len + id_len;
        ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO);
        sp = (struct scsi_vpd_scsi_ports *)ctsio->kern_data_ptr;
        ctsio->kern_sg_entries = 0;
@@ -10098,19 +10103,22 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_s
                                continue;
                        p = port->targ_port % CTL_MAX_PORTS + g * CTL_MAX_PORTS;
                        scsi_ulto2b(p, pd->relative_port_id);
-                       scsi_ulto2b(0, pd->initiator_transportid_length);
+                       if (port->init_devid && g == pg) {
+                               iid_len = port->init_devid->len;
+                               memcpy(pd->initiator_transportid,
+                                   port->init_devid->data, 
port->init_devid->len);
+                       } else
+                               iid_len = 0;
+                       scsi_ulto2b(iid_len, pd->initiator_transportid_length);
                        pdc = (struct scsi_vpd_port_designation_cont *)
-                           &pd->initiator_transportid[0];
+                           (&pd->initiator_transportid[iid_len]);
                        if (port->port_devid && g == pg) {
                                id_len = port->port_devid->len;
-                               scsi_ulto2b(port->port_devid->len,
-                                   pdc->target_port_descriptors_length);
                                memcpy(pdc->target_port_descriptors,
                                    port->port_devid->data, 
port->port_devid->len);
-                       } else {
+                       } else
                                id_len = 0;
-                               scsi_ulto2b(0, 
pdc->target_port_descriptors_length);
-                       }
+                       scsi_ulto2b(id_len, 
pdc->target_port_descriptors_length);
                        pd = (struct scsi_vpd_port_designation *)
                            ((uint8_t *)pdc->target_port_descriptors + id_len);
                }
@@ -10259,6 +10267,9 @@ ctl_inquiry_evpd(struct ctl_scsiio *ctsi
        case SVPD_SCSI_PORTS:
                retval = ctl_inquiry_evpd_scsi_ports(ctsio, alloc_len);
                break;
+       case SVPD_SCSI_TPC:
+               retval = ctl_inquiry_evpd_tpc(ctsio, alloc_len);
+               break;
        case SVPD_BLOCK_LIMITS:
                retval = ctl_inquiry_evpd_block_limits(ctsio, alloc_len);
                break;
@@ -10289,7 +10300,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio
        struct ctl_lun *lun;
        char *val;
        uint32_t alloc_len;
-       int is_fc;
+       ctl_port_type port_type;
 
        ctl_softc = control_softc;
 
@@ -10298,11 +10309,10 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio
         * We treat the ioctl front end, and any SCSI adapters, as packetized
         * SCSI front ends.
         */
-       if 
(ctl_softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]->port_type !=
-           CTL_PORT_FC)
-               is_fc = 0;
-       else
-               is_fc = 1;
+       port_type = ctl_softc->ctl_ports[
+           ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]->port_type;
+       if (port_type == CTL_PORT_IOCTL || port_type == CTL_PORT_INTERNAL)
+               port_type = CTL_PORT_SCSI;
 
        lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
        cdb = (struct scsi_inquiry *)ctsio->cdb;
@@ -10381,7 +10391,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio
                inq_ptr->device = (SID_QUAL_BAD_LU << 5) | T_NODEVICE;
 
        /* RMB in byte 2 is 0 */
-       inq_ptr->version = SCSI_REV_SPC3;
+       inq_ptr->version = SCSI_REV_SPC4;
 
        /*
         * According to SAM-3, even if a device only supports a single
@@ -10406,17 +10416,18 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio
        CTL_DEBUG_PRINT(("additional_length = %d\n",
                         inq_ptr->additional_length));
 
-       inq_ptr->spc3_flags = SPC3_SID_TPGS_IMPLICIT;
+       inq_ptr->spc3_flags = SPC3_SID_3PC;
+       if (!ctl_is_single)
+               inq_ptr->spc3_flags |= SPC3_SID_TPGS_IMPLICIT;
        /* 16 bit addressing */
-       if (is_fc == 0)
+       if (port_type == CTL_PORT_SCSI)
                inq_ptr->spc2_flags = SPC2_SID_ADDR16;
        /* XXX set the SID_MultiP bit here if we're actually going to
           respond on multiple ports */
        inq_ptr->spc2_flags |= SPC2_SID_MultiP;
 
        /* 16 bit data bus, synchronous transfers */
-       /* XXX these flags don't apply for FC */
-       if (is_fc == 0)
+       if (port_type == CTL_PORT_SCSI)
                inq_ptr->flags = SID_WBus16 | SID_Sync;
        /*
         * XXX KDM do we want to support tagged queueing on the control
@@ -10477,33 +10488,36 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio
         * and Selection) and Information Unit transfers on both the
         * control and array devices.
         */
-       if (is_fc == 0)
+       if (port_type == CTL_PORT_SCSI)
                inq_ptr->spi3data = SID_SPI_CLOCK_DT_ST | SID_SPI_QAS |
                                    SID_SPI_IUS;
 
-       /* SAM-3 */
-       scsi_ulto2b(0x0060, inq_ptr->version1);
-       /* SPC-3 (no version claimed) XXX should we claim a version? */
-       scsi_ulto2b(0x0300, inq_ptr->version2);
-       if (is_fc) {
+       /* SAM-5 (no version claimed) */
+       scsi_ulto2b(0x00A0, inq_ptr->version1);
+       /* SPC-4 (no version claimed) */
+       scsi_ulto2b(0x0460, inq_ptr->version2);
+       if (port_type == CTL_PORT_FC) {
                /* FCP-2 ANSI INCITS.350:2003 */
                scsi_ulto2b(0x0917, inq_ptr->version3);
-       } else {
+       } else if (port_type == CTL_PORT_SCSI) {
                /* SPI-4 ANSI INCITS.362:200x */
                scsi_ulto2b(0x0B56, inq_ptr->version3);
+       } else if (port_type == CTL_PORT_ISCSI) {
+               /* iSCSI (no version claimed) */
+               scsi_ulto2b(0x0960, inq_ptr->version3);
+       } else if (port_type == CTL_PORT_SAS) {
+               /* SAS (no version claimed) */
+               scsi_ulto2b(0x0BE0, inq_ptr->version3);
        }
 
        if (lun == NULL) {
-               /* SBC-2 (no version claimed) XXX should we claim a version? */
-               scsi_ulto2b(0x0320, inq_ptr->version4);
+               /* SBC-3 (no version claimed) */
+               scsi_ulto2b(0x04C0, inq_ptr->version4);
        } else {
                switch (lun->be_lun->lun_type) {
                case T_DIRECT:
-                       /*
-                        * SBC-2 (no version claimed) XXX should we claim a
-                        * version?
-                        */
-                       scsi_ulto2b(0x0320, inq_ptr->version4);
+                       /* SBC-3 (no version claimed) */
+                       scsi_ulto2b(0x04C0, inq_ptr->version4);
                        break;
                case T_PROCESSOR:
                default:

Modified: head/sys/cam/ctl/ctl_cmd_table.c
==============================================================================
--- head/sys/cam/ctl/ctl_cmd_table.c    Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_cmd_table.c    Wed Jul 16 15:57:17 2014        
(r268767)
@@ -190,6 +190,156 @@ const struct ctl_cmd_entry ctl_cmd_table
 /* 08-1f */
 };
 
+/* 83 EXTENDED COPY */
+const struct ctl_cmd_entry ctl_cmd_table_83[32] =
+{
+/* 00 EXTENDED COPY (LID1) */
+{ctl_extended_copy_lid1, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
+                                           CTL_FLAG_DATA_OUT,
+ CTL_LUN_PAT_NONE,
+ 16, { 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 01 EXTENDED COPY (LID4) */
+{ctl_extended_copy_lid4, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
+                                           CTL_FLAG_DATA_OUT,
+ CTL_LUN_PAT_NONE,
+ 16, { 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 02 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 03 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 04 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 05 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 06 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 07 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 08 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 09 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0A */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0B */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0C */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0D */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0E */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 0F */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 10 POPULATE TOKEN */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 11 WRITE USING TOKEN */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 12 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 13 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 14 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 15 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 16 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 17 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 18 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 19 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 1A */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 1B */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 1C COPY OPERATION ABORT */
+{ctl_copy_operation_abort, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
+                                             CTL_FLAG_DATA_NONE,
+ CTL_LUN_PAT_NONE,
+ 16, { 0x1c, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x07}},
+};
+
+/* 84 RECEIVE COPY STATUS */
+const struct ctl_cmd_entry ctl_cmd_table_84[32] =
+{
+/* 00 RECEIVE COPY STATUS (LID1) */
+{ctl_receive_copy_status_lid1, CTL_SERIDX_RD_CAP,
+ CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_FLAG_DATA_IN,
+ CTL_LUN_PAT_NONE,
+ 16, {0x00, 0xff, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 01 RECEIVE COPY DATA (LID1) */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 02 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 03 RECEIVE COPY OPERATING PARAMETERS */
+{ctl_receive_copy_operating_parameters, CTL_SERIDX_RD_CAP,
+ CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_CMD_FLAG_OK_ON_STOPPED |
+ CTL_CMD_FLAG_OK_ON_INOPERABLE |
+ CTL_CMD_FLAG_OK_ON_SECONDARY |
+ CTL_FLAG_DATA_IN,
+ CTL_LUN_PAT_NONE,
+ 16, {0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 04 RECEIVE COPY FAILURE DETAILS (LID1) */
+{ctl_receive_copy_failure_details, CTL_SERIDX_RD_CAP,
+ CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_FLAG_DATA_IN,
+ CTL_LUN_PAT_NONE,
+ 16, {0x04, 0xff, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 05 RECEIVE COPY STATUS (LID4) */
+{ctl_receive_copy_status_lid4, CTL_SERIDX_RD_CAP,
+ CTL_CMD_FLAG_OK_ON_BOTH |
+ CTL_FLAG_DATA_IN,
+ CTL_LUN_PAT_NONE,
+ 16, {0x05, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 
0x07}},
+
+/* 06 RECEIVE COPY DATA (LID4)*/
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 07 RECEIVE ROD TOKEN INFORMATION */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 08 REPORT ALL ROD TOKENS */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+};
+
 /* 9E SERVICE ACTION IN(16) */
 const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
 {
@@ -844,10 +994,12 @@ const struct ctl_cmd_entry ctl_cmd_table
 {NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
 
 /* 83 EXTENDED COPY */
-{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+{__DECONST(ctl_opfunc *, ctl_cmd_table_83), CTL_SERIDX_INVLD, CTL_CMD_FLAG_SA5,
+ CTL_LUN_PAT_NONE},
 
 /* 84 RECEIVE COPY RESULTS */
-{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+{__DECONST(ctl_opfunc *, ctl_cmd_table_84), CTL_SERIDX_INVLD, CTL_CMD_FLAG_SA5,
+ CTL_LUN_PAT_NONE},
 
 /* 85 */
 {NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},

Modified: head/sys/cam/ctl/ctl_frontend.c
==============================================================================
--- head/sys/cam/ctl/ctl_frontend.c     Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_frontend.c     Wed Jul 16 15:57:17 2014        
(r268767)
@@ -234,6 +234,8 @@ ctl_port_deregister(struct ctl_port *por
        port->port_devid = NULL;
        free(port->target_devid, M_CTL);
        port->target_devid = NULL;
+       free(port->init_devid, M_CTL);
+       port->init_devid = NULL;
        for (i = 0; i < port->max_initiators; i++)
                free(port->wwpn_iid[i].name, M_CTL);
        free(port->wwpn_iid, M_CTL);

Modified: head/sys/cam/ctl/ctl_frontend.h
==============================================================================
--- head/sys/cam/ctl/ctl_frontend.h     Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_frontend.h     Wed Jul 16 15:57:17 2014        
(r268767)
@@ -242,6 +242,7 @@ struct ctl_port {
        ctl_options_t   options;                /* passed to CTL */
        struct ctl_devid *port_devid;           /* passed to CTL */
        struct ctl_devid *target_devid;         /* passed to CTL */
+       struct ctl_devid *init_devid;           /* passed to CTL */
        STAILQ_ENTRY(ctl_port) fe_links;        /* used by CTL */
        STAILQ_ENTRY(ctl_port) links;           /* used by CTL */
 };

Modified: head/sys/cam/ctl/ctl_frontend_iscsi.c
==============================================================================
--- head/sys/cam/ctl/ctl_frontend_iscsi.c       Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_frontend_iscsi.c       Wed Jul 16 15:57:17 2014        
(r268767)
@@ -2702,7 +2702,7 @@ cfiscsi_scsi_command_done(union ctl_io *
         * Do not return status for aborted commands.
         * There are exceptions, but none supported by CTL yet.
         */
-       if (io->io_hdr.status == CTL_CMD_ABORTED &&
+       if ((io->io_hdr.flags & CTL_FLAG_ABORT) &&
            (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) {
                ctl_free_io(io);
                icl_pdu_free(request);

Modified: head/sys/cam/ctl/ctl_private.h
==============================================================================
--- head/sys/cam/ctl/ctl_private.h      Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_private.h      Wed Jul 16 15:57:17 2014        
(r268767)
@@ -373,6 +373,7 @@ struct ctl_devid {
  */
 #define NUM_TARGET_PORT_GROUPS 2
 
+struct tpc_list;
 struct ctl_lun {
        struct mtx                      lun_lock;
        struct ctl_id                   target;
@@ -403,6 +404,7 @@ struct ctl_lun {
        uint8_t                         res_type;
        uint8_t                         write_buffer[524288];
        struct ctl_devid                *lun_devid;
+       TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;
 };
 
 typedef enum {
@@ -467,6 +469,8 @@ struct ctl_softc {
 extern const struct ctl_cmd_entry ctl_cmd_table[256];
 
 uint32_t ctl_get_initindex(struct ctl_nexus *nexus);
+uint32_t ctl_get_resindex(struct ctl_nexus *nexus);
+uint32_t ctl_port_idx(int port_num);
 int ctl_pool_create(struct ctl_softc *ctl_softc, ctl_pool_type pool_type,
                    uint32_t total_ctl_io, struct ctl_io_pool **npool);
 void ctl_pool_free(struct ctl_io_pool *pool);
@@ -498,6 +502,17 @@ int ctl_report_supported_tmf(struct ctl_
 int ctl_report_timestamp(struct ctl_scsiio *ctsio);
 int ctl_isc(struct ctl_scsiio *ctsio);
 
+void ctl_tpc_init(struct ctl_lun *lun);
+void ctl_tpc_shutdown(struct ctl_lun *lun);
+int ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len);
+int ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio);
+int ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio);
+int ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio);
+int ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio);
+int ctl_extended_copy_lid1(struct ctl_scsiio *ctsio);
+int ctl_extended_copy_lid4(struct ctl_scsiio *ctsio);
+int ctl_copy_operation_abort(struct ctl_scsiio *ctsio);
+
 #endif /* _KERNEL */
 
 #endif /* _CTL_PRIVATE_H_ */

Modified: head/sys/cam/ctl/ctl_ser_table.c
==============================================================================
--- head/sys/cam/ctl/ctl_ser_table.c    Wed Jul 16 14:08:01 2014        
(r268766)
+++ head/sys/cam/ctl/ctl_ser_table.c    Wed Jul 16 15:57:17 2014        
(r268767)
@@ -69,7 +69,7 @@ ctl_serialize_table[CTL_SERIDX_COUNT][CT
 /*MD_SEL  */{   bK, bK, bK, bK, bK,  bK,  bK,  pS, pS,  bK, pS,  bK, bK},
 /*RQ_SNS  */{   pS, pS, pS, pS, pS,  pS,  bK,  pS, pS,  bK, pS,  bK, bK},
 /*INQ     */{   pS, pS, pS, pS, pS,  pS,  bK,  pS, pS,  pS, pS,  bK, bK},
-/*RD_CAP  */{   pS, pS, pS, pS, pS,  pS,  bK,  pS, pS,  bK, pS,  bK, bK},
+/*RD_CAP  */{   pS, pS, pS, pS, pS,  pS,  bK,  pS, pS,  pS, pS,  bK, bK},
 /*RES     */{   bK, bK, bK, bK, bK,  bK,  bK,  pS, bK,  bK, bK,  bK, bK},
 /*LOG_SNS */{   pS, pS, pS, pS, pS,  bK,  bK,  pS, pS,  bK, pS,  bK, bK},
 /*FORMAT  */{   pS, bK, bK, bK, bK,  bK,  pS,  pS, bK,  bK, bK,  bK, bK},

Added: head/sys/cam/ctl/ctl_tpc.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/cam/ctl/ctl_tpc.c  Wed Jul 16 15:57:17 2014        (r268767)
@@ -0,0 +1,1370 @@
+/*-
+ * Copyright (c) 2014 Alexander Motin <m...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <machine/atomic.h>
+
+#include <cam/cam.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/ctl/ctl_io.h>
+#include <cam/ctl/ctl.h>
+#include <cam/ctl/ctl_frontend.h>
+#include <cam/ctl/ctl_frontend_internal.h>
+#include <cam/ctl/ctl_util.h>
+#include <cam/ctl/ctl_backend.h>
+#include <cam/ctl/ctl_ioctl.h>
+#include <cam/ctl/ctl_ha.h>
+#include <cam/ctl/ctl_private.h>
+#include <cam/ctl/ctl_debug.h>
+#include <cam/ctl/ctl_scsi_all.h>
+#include <cam/ctl/ctl_tpc.h>
+#include <cam/ctl/ctl_error.h>
+
+#define        TPC_MAX_CSCDS   64
+#define        TPC_MAX_SEGS    64
+#define        TPC_MAX_SEG     0
+#define        TPC_MAX_LIST    8192
+#define        TPC_MAX_INLINE  0
+#define        TPC_MAX_LISTS   255
+#define        TPC_MAX_IO_SIZE (1024 * 1024)
+
+MALLOC_DEFINE(M_CTL_TPC, "ctltpc", "CTL TPC");
+
+typedef enum {
+       TPC_ERR_RETRY           = 0x000,
+       TPC_ERR_FAIL            = 0x001,
+       TPC_ERR_MASK            = 0x0ff,
+       TPC_ERR_NO_DECREMENT    = 0x100
+} tpc_error_action;
+
+struct tpc_list;
+TAILQ_HEAD(runl, tpc_io);
+struct tpc_io {
+       union ctl_io            *io;
+       uint64_t                 lun;
+       struct tpc_list         *list;
+       struct runl              run;
+       TAILQ_ENTRY(tpc_io)      rlinks;
+       TAILQ_ENTRY(tpc_io)      links;
+};
+
+struct tpc_list {
+       uint8_t                  service_action;
+       int                      init_port;
+       uint16_t                 init_idx;
+       uint32_t                 list_id;
+       uint8_t                  flags;
+       uint8_t                 *params;
+       struct scsi_ec_cscd     *cscd;
+       struct scsi_ec_segment  *seg[TPC_MAX_SEGS];
+       uint8_t                 *inl;
+       int                      ncscd;
+       int                      nseg;
+       int                      leninl;
+       int                      curseg;
+       off_t                    curbytes;
+       int                      curops;
+       int                      stage;
+       uint8_t                 *buf;
+       int                      segbytes;
+       int                      tbdio;
+       int                      error;
+       int                      abort;
+       int                      completed;
+       TAILQ_HEAD(, tpc_io)     allio;
+       struct scsi_sense_data   sense_data;
+       uint8_t                  sense_len;
+       uint8_t                  scsi_status;
+       struct ctl_scsiio       *ctsio;
+       struct ctl_lun          *lun;
+       TAILQ_ENTRY(tpc_list)    links;
+};
+
+void
+ctl_tpc_init(struct ctl_lun *lun)
+{
+
+       TAILQ_INIT(&lun->tpc_lists);
+}
+
+void
+ctl_tpc_shutdown(struct ctl_lun *lun)
+{
+       struct tpc_list *list;
+
+       while ((list = TAILQ_FIRST(&lun->tpc_lists)) != NULL) {
+               TAILQ_REMOVE(&lun->tpc_lists, list, links);
+               KASSERT(list->completed,
+                   ("Not completed TPC (%p) on shutdown", list));
+               free(list, M_CTL);
+       }
+}
+
+int
+ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len)
+{
+       struct scsi_vpd_tpc *tpc_ptr;
+       struct scsi_vpd_tpc_descriptor *d_ptr;
+       struct scsi_vpd_tpc_descriptor_sc *sc_ptr;
+       struct scsi_vpd_tpc_descriptor_sc_descr *scd_ptr;
+       struct scsi_vpd_tpc_descriptor_pd *pd_ptr;
+       struct scsi_vpd_tpc_descriptor_sd *sd_ptr;
+       struct scsi_vpd_tpc_descriptor_sdid *sdid_ptr;
+       struct scsi_vpd_tpc_descriptor_gco *gco_ptr;
+       struct ctl_lun *lun;
+       int data_len;
+
+       lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+       data_len = sizeof(struct scsi_vpd_tpc) +
+           roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sc) +
+            2 * sizeof(struct scsi_vpd_tpc_descriptor_sc_descr) + 7, 4) +
+           sizeof(struct scsi_vpd_tpc_descriptor_pd) +
+           roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sd) + 4, 4) +
+           roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sdid) + 2, 4) +
+           sizeof(struct scsi_vpd_tpc_descriptor_gco);
+
+       ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO);
+       tpc_ptr = (struct scsi_vpd_tpc *)ctsio->kern_data_ptr;
+       ctsio->kern_sg_entries = 0;
+
+       if (data_len < alloc_len) {
+               ctsio->residual = alloc_len - data_len;
+               ctsio->kern_data_len = data_len;
+               ctsio->kern_total_len = data_len;
+       } else {
+               ctsio->residual = 0;
+               ctsio->kern_data_len = alloc_len;
+               ctsio->kern_total_len = alloc_len;
+       }
+       ctsio->kern_data_resid = 0;
+       ctsio->kern_rel_offset = 0;
+       ctsio->kern_sg_entries = 0;
+
+       /*
+        * The control device is always connected.  The disk device, on the
+        * other hand, may not be online all the time.
+        */
+       if (lun != NULL)
+               tpc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) |
+                                    lun->be_lun->lun_type;
+       else
+               tpc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT;
+       tpc_ptr->page_code = SVPD_SCSI_TPC;
+       scsi_ulto2b(data_len - 4, tpc_ptr->page_length);
+
+       /* Supported commands */
+       d_ptr = (struct scsi_vpd_tpc_descriptor *)&tpc_ptr->descr[0];
+       sc_ptr = (struct scsi_vpd_tpc_descriptor_sc *)d_ptr;
+       scsi_ulto2b(SVPD_TPC_SC, sc_ptr->desc_type);
+       sc_ptr->list_length = 2 * sizeof(*scd_ptr) + 7;
+       scsi_ulto2b(roundup2(1 + sc_ptr->list_length, 4), sc_ptr->desc_length);
+       scd_ptr = &sc_ptr->descr[0];
+       scd_ptr->opcode = EXTENDED_COPY;
+       scd_ptr->sa_length = 3;
+       scd_ptr->supported_service_actions[0] = EC_EC_LID1;
+       scd_ptr->supported_service_actions[1] = EC_EC_LID4;
+       scd_ptr->supported_service_actions[2] = EC_COA;
+       scd_ptr = (struct scsi_vpd_tpc_descriptor_sc_descr *)
+           &scd_ptr->supported_service_actions[scd_ptr->sa_length];
+       scd_ptr->opcode = RECEIVE_COPY_STATUS;
+       scd_ptr->sa_length = 4;
+       scd_ptr->supported_service_actions[0] = RCS_RCS_LID1;
+       scd_ptr->supported_service_actions[1] = RCS_RCFD;
+       scd_ptr->supported_service_actions[2] = RCS_RCS_LID4;
+       scd_ptr->supported_service_actions[3] = RCS_RCOP;
+
+       /* Parameter data. */
+       d_ptr = (struct scsi_vpd_tpc_descriptor *)
+           (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
+       pd_ptr = (struct scsi_vpd_tpc_descriptor_pd *)d_ptr;
+       scsi_ulto2b(SVPD_TPC_PD, pd_ptr->desc_type);
+       scsi_ulto2b(sizeof(*pd_ptr) - 4, pd_ptr->desc_length);
+       scsi_ulto2b(TPC_MAX_CSCDS, pd_ptr->maximum_cscd_descriptor_count);
+       scsi_ulto2b(TPC_MAX_SEGS, pd_ptr->maximum_segment_descriptor_count);
+       scsi_ulto4b(TPC_MAX_LIST, pd_ptr->maximum_descriptor_list_length);
+       scsi_ulto4b(TPC_MAX_INLINE, pd_ptr->maximum_inline_data_length);
+
+       /* Supported Descriptors */
+       d_ptr = (struct scsi_vpd_tpc_descriptor *)
+           (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
+       sd_ptr = (struct scsi_vpd_tpc_descriptor_sd *)d_ptr;
+       scsi_ulto2b(SVPD_TPC_SD, sd_ptr->desc_type);
+       scsi_ulto2b(roundup2(sizeof(*sd_ptr) - 4 + 4, 4), sd_ptr->desc_length);
+       sd_ptr->list_length = 4;
+       sd_ptr->supported_descriptor_codes[0] = EC_SEG_B2B;
+       sd_ptr->supported_descriptor_codes[1] = EC_SEG_VERIFY;
+       sd_ptr->supported_descriptor_codes[2] = EC_SEG_REGISTER_KEY;
+       sd_ptr->supported_descriptor_codes[3] = EC_CSCD_ID;
+
+       /* Supported CSCD Descriptor IDs */
+       d_ptr = (struct scsi_vpd_tpc_descriptor *)
+           (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
+       sdid_ptr = (struct scsi_vpd_tpc_descriptor_sdid *)d_ptr;
+       scsi_ulto2b(SVPD_TPC_SDID, sdid_ptr->desc_type);
+       scsi_ulto2b(roundup2(sizeof(*sdid_ptr) - 4 + 2, 4), 
sdid_ptr->desc_length);
+       scsi_ulto2b(2, sdid_ptr->list_length);
+       scsi_ulto2b(0xffff, &sdid_ptr->supported_descriptor_ids[0]);
+
+       /* General Copy Operations */
+       d_ptr = (struct scsi_vpd_tpc_descriptor *)
+           (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
+       gco_ptr = (struct scsi_vpd_tpc_descriptor_gco *)d_ptr;
+       scsi_ulto2b(SVPD_TPC_GCO, gco_ptr->desc_type);
+       scsi_ulto2b(sizeof(*gco_ptr) - 4, gco_ptr->desc_length);
+       scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->total_concurrent_copies);
+       scsi_ulto4b(TPC_MAX_LISTS, 
gco_ptr->maximum_identified_concurrent_copies);
+       scsi_ulto4b(TPC_MAX_SEG, gco_ptr->maximum_segment_length);
+       gco_ptr->data_segment_granularity = 0;
+       gco_ptr->inline_data_granularity = 0;
+
+       ctsio->scsi_status = SCSI_STATUS_OK;
+       ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+       ctsio->be_move_done = ctl_config_move_done;
+       ctl_datamove((union ctl_io *)ctsio);
+
+       return (CTL_RETVAL_COMPLETE);
+}
+
+int
+ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio)
+{
+       struct ctl_lun *lun;
+       struct scsi_receive_copy_operating_parameters *cdb;
+       struct scsi_receive_copy_operating_parameters_data *data;
+       int retval;
+       int alloc_len, total_len;
+
+       CTL_DEBUG_PRINT(("ctl_report_supported_tmf\n"));
+
+       cdb = (struct scsi_receive_copy_operating_parameters *)ctsio->cdb;
+       lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+       retval = CTL_RETVAL_COMPLETE;
+
+       total_len = sizeof(*data) + 4;
+       alloc_len = scsi_4btoul(cdb->length);
+
+       ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+
+       ctsio->kern_sg_entries = 0;
+
+       if (total_len < alloc_len) {
+               ctsio->residual = alloc_len - total_len;
+               ctsio->kern_data_len = total_len;
+               ctsio->kern_total_len = total_len;
+       } else {
+               ctsio->residual = 0;
+               ctsio->kern_data_len = alloc_len;
+               ctsio->kern_total_len = alloc_len;
+       }
+       ctsio->kern_data_resid = 0;
+       ctsio->kern_rel_offset = 0;
+
+       data = (struct scsi_receive_copy_operating_parameters_data 
*)ctsio->kern_data_ptr;
+       scsi_ulto4b(sizeof(*data) - 4 + 4, data->length);
+       data->snlid = RCOP_SNLID;
+       scsi_ulto2b(TPC_MAX_CSCDS, data->maximum_cscd_descriptor_count);
+       scsi_ulto2b(TPC_MAX_SEGS, data->maximum_segment_descriptor_count);
+       scsi_ulto4b(TPC_MAX_LIST, data->maximum_descriptor_list_length);
+       scsi_ulto4b(TPC_MAX_SEG, data->maximum_segment_length);
+       scsi_ulto4b(TPC_MAX_INLINE, data->maximum_inline_data_length);
+       scsi_ulto4b(0, data->held_data_limit);
+       scsi_ulto4b(0, data->maximum_stream_device_transfer_size);
+       scsi_ulto2b(TPC_MAX_LISTS, data->total_concurrent_copies);
+       data->maximum_concurrent_copies = TPC_MAX_LISTS;
+       data->data_segment_granularity = 0;
+       data->inline_data_granularity = 0;
+       data->held_data_granularity = 0;
+       data->implemented_descriptor_list_length = 4;
+       data->list_of_implemented_descriptor_type_codes[0] = EC_SEG_B2B;
+       data->list_of_implemented_descriptor_type_codes[1] = EC_SEG_VERIFY;
+       data->list_of_implemented_descriptor_type_codes[2] = 
EC_SEG_REGISTER_KEY;
+       data->list_of_implemented_descriptor_type_codes[3] = EC_CSCD_ID;
+
+       ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+       ctsio->be_move_done = ctl_config_move_done;
+
+       ctl_datamove((union ctl_io *)ctsio);
+       return (retval);
+}
+
+int
+ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio)
+{
+       struct ctl_lun *lun;
+       struct scsi_receive_copy_status_lid1 *cdb;
+       struct scsi_receive_copy_status_lid1_data *data;
+       struct tpc_list *list;
+       struct tpc_list list_copy;
+       int retval;
+       int alloc_len, total_len;
+       uint32_t list_id;
+
+       CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid1\n"));
+
+       cdb = (struct scsi_receive_copy_status_lid1 *)ctsio->cdb;
+       lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+       retval = CTL_RETVAL_COMPLETE;
+
+       list_id = cdb->list_identifier;
+       mtx_lock(&lun->lun_lock);
+       TAILQ_FOREACH(list, &lun->tpc_lists, links) {
+               if ((list->flags & EC_LIST_ID_USAGE_MASK) !=
+                    EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
+                       break;
+       }
+       if (list == NULL) {
+               mtx_unlock(&lun->lun_lock);
+               ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
+                   /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
+                   /*bit*/ 0);
+               ctl_done((union ctl_io *)ctsio);
+               return (retval);
+       }
+       list_copy = *list;
+       if (list->completed) {
+               TAILQ_REMOVE(&lun->tpc_lists, list, links);
+               free(list, M_CTL);
+       }
+       mtx_unlock(&lun->lun_lock);
+
+       total_len = sizeof(*data);
+       alloc_len = scsi_4btoul(cdb->length);
+
+       ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+
+       ctsio->kern_sg_entries = 0;
+
+       if (total_len < alloc_len) {
+               ctsio->residual = alloc_len - total_len;
+               ctsio->kern_data_len = total_len;
+               ctsio->kern_total_len = total_len;
+       } else {
+               ctsio->residual = 0;
+               ctsio->kern_data_len = alloc_len;
+               ctsio->kern_total_len = alloc_len;
+       }
+       ctsio->kern_data_resid = 0;
+       ctsio->kern_rel_offset = 0;
+
+       data = (struct scsi_receive_copy_status_lid1_data 
*)ctsio->kern_data_ptr;
+       scsi_ulto4b(sizeof(*data) - 4, data->available_data);
+       if (list_copy.completed) {
+               if (list_copy.error || list_copy.abort)
+                       data->copy_command_status = RCS_CCS_ERROR;
+               else
+                       data->copy_command_status = RCS_CCS_COMPLETED;
+       } else
+               data->copy_command_status = RCS_CCS_INPROG;
+       scsi_ulto2b(list_copy.curseg, data->segments_processed);
+       if (list_copy.curbytes <= UINT32_MAX) {
+               data->transfer_count_units = RCS_TC_BYTES;
+               scsi_ulto4b(list_copy.curbytes, data->transfer_count);
+       } else {
+               data->transfer_count_units = RCS_TC_MBYTES;
+               scsi_ulto4b(list_copy.curbytes >> 20, data->transfer_count);
+       }
+
+       ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+       ctsio->be_move_done = ctl_config_move_done;
+
+       ctl_datamove((union ctl_io *)ctsio);
+       return (retval);
+}
+
+int
+ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio)
+{
+       struct ctl_lun *lun;
+       struct scsi_receive_copy_failure_details *cdb;
+       struct scsi_receive_copy_failure_details_data *data;
+       struct tpc_list *list;
+       struct tpc_list list_copy;
+       int retval;
+       int alloc_len, total_len;
+       uint32_t list_id;
+
+       CTL_DEBUG_PRINT(("ctl_receive_copy_failure_details\n"));
+
+       cdb = (struct scsi_receive_copy_failure_details *)ctsio->cdb;
+       lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+
+       retval = CTL_RETVAL_COMPLETE;
+
+       list_id = cdb->list_identifier;
+       mtx_lock(&lun->lun_lock);
+       TAILQ_FOREACH(list, &lun->tpc_lists, links) {
+               if (list->completed && (list->flags & EC_LIST_ID_USAGE_MASK) !=
+                    EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
+                       break;
+       }
+       if (list == NULL) {
+               mtx_unlock(&lun->lun_lock);
+               ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
+                   /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
+                   /*bit*/ 0);
+               ctl_done((union ctl_io *)ctsio);
+               return (retval);
+       }
+       list_copy = *list;
+       TAILQ_REMOVE(&lun->tpc_lists, list, links);
+       free(list, M_CTL);
+       mtx_unlock(&lun->lun_lock);
+
+       total_len = sizeof(*data) + list_copy.sense_len;
+       alloc_len = scsi_4btoul(cdb->length);
+
+       ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+
+       ctsio->kern_sg_entries = 0;
+
+       if (total_len < alloc_len) {
+               ctsio->residual = alloc_len - total_len;
+               ctsio->kern_data_len = total_len;
+               ctsio->kern_total_len = total_len;
+       } else {
+               ctsio->residual = 0;
+               ctsio->kern_data_len = alloc_len;
+               ctsio->kern_total_len = alloc_len;
+       }
+       ctsio->kern_data_resid = 0;
+       ctsio->kern_rel_offset = 0;
+
+       data = (struct scsi_receive_copy_failure_details_data 
*)ctsio->kern_data_ptr;
+       if (list_copy.completed && (list_copy.error || list_copy.abort)) {
+               scsi_ulto4b(sizeof(*data) - 4, data->available_data);
+               data->copy_command_status = RCS_CCS_ERROR;
+       } else
+               scsi_ulto4b(0, data->available_data);
+       scsi_ulto2b(list_copy.sense_len, data->sense_data_length);
+       memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len);
+
+       ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+       ctsio->be_move_done = ctl_config_move_done;
+
+       ctl_datamove((union ctl_io *)ctsio);
+       return (retval);
+}
+
+int
+ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio)
+{
+       struct ctl_lun *lun;
+       struct scsi_receive_copy_status_lid4 *cdb;
+       struct scsi_receive_copy_status_lid4_data *data;
+       struct tpc_list *list;
+       struct tpc_list list_copy;
+       int retval;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to