[SCSI] mpt2sas: T10 DIF Support
authorEric Moore <eric.moore@lsi.com>
Mon, 18 May 2009 18:59:41 +0000 (12:59 -0600)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Sat, 23 May 2009 20:44:16 +0000 (15:44 -0500)
This add support for type 1 and 3 DIF support per the Oracle API.

Signed-off-by: Eric Moore <eric.moore@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c

index 36b1d1052ba1281eb6e33d8fe154d7fce87aacf1..aba81fb320b798ca9647bc3186ce2a78a3ed2006 100644 (file)
@@ -61,6 +61,7 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport_sas.h>
 #include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
 
 #include "mpt2sas_debug.h"
 
index e3a7967259e75fe5cfac5f5101a4e8f2912992f6..5394f6196416f0c8d4f96e08526a55d2747c13d9 100644 (file)
@@ -2389,6 +2389,106 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
        }
 }
 
+/**
+ * _scsih_setup_eedp - setup MPI request for EEDP transfer
+ * @scmd: pointer to scsi command object
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ *
+ * Supporting protection 1 and 3.
+ *
+ * Returns nothing
+ */
+static void
+_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
+{
+       u16 eedp_flags;
+       unsigned char prot_op = scsi_get_prot_op(scmd);
+       unsigned char prot_type = scsi_get_prot_type(scmd);
+
+       if (prot_type == SCSI_PROT_DIF_TYPE0 ||
+          prot_type == SCSI_PROT_DIF_TYPE2 ||
+          prot_op == SCSI_PROT_NORMAL)
+               return;
+
+       if (prot_op ==  SCSI_PROT_READ_STRIP)
+               eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
+       else if (prot_op ==  SCSI_PROT_WRITE_INSERT)
+               eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+       else
+               return;
+
+       mpi_request->EEDPBlockSize = scmd->device->sector_size;
+
+       switch (prot_type) {
+       case SCSI_PROT_DIF_TYPE1:
+
+               /*
+               * enable ref/guard checking
+               * auto increment ref tag
+               */
+               mpi_request->EEDPFlags = eedp_flags |
+                   MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+               mpi_request->CDB.EEDP32.PrimaryReferenceTag =
+                   cpu_to_be32(scsi_get_lba(scmd));
+
+               break;
+
+       case SCSI_PROT_DIF_TYPE3:
+
+               /*
+               * enable guard checking
+               */
+               mpi_request->EEDPFlags = eedp_flags |
+                   MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+
+               break;
+       }
+}
+
+/**
+ * _scsih_eedp_error_handling - return sense code for EEDP errors
+ * @scmd: pointer to scsi command object
+ * @ioc_status: ioc status
+ *
+ * Returns nothing
+ */
+static void
+_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
+{
+       u8 ascq;
+       u8 sk;
+       u8 host_byte;
+
+       switch (ioc_status) {
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               ascq = 0x01;
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               ascq = 0x02;
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               ascq = 0x03;
+               break;
+       default:
+               ascq = 0x00;
+               break;
+       }
+
+       if (scmd->sc_data_direction == DMA_TO_DEVICE) {
+               sk = ILLEGAL_REQUEST;
+               host_byte = DID_ABORT;
+       } else {
+               sk = ABORTED_COMMAND;
+               host_byte = DID_OK;
+       }
+
+       scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq);
+       scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) |
+           SAM_STAT_CHECK_CONDITION;
+}
+
 /**
  * scsih_qcmd - main scsi request entry point
  * @scmd: pointer to scsi command object
@@ -2470,6 +2570,7 @@ scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
        }
        mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
        memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
+       _scsih_setup_eedp(scmd, mpi_request);
        mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
        if (sas_device_priv_data->sas_target->flags &
            MPT_TARGET_FLAGS_RAID_COMPONENT)
@@ -2604,6 +2705,15 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
        case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
                desc_ioc_state = "scsi ext terminated";
                break;
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+               desc_ioc_state = "eedp guard error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+               desc_ioc_state = "eedp ref tag error";
+               break;
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               desc_ioc_state = "eedp app tag error";
+               break;
        default:
                desc_ioc_state = "unknown";
                break;
@@ -2939,6 +3049,11 @@ scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
                        scmd->result = DID_RESET << 16;
                break;
 
+       case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
+       case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
+       case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
+               _scsih_eedp_error_handling(scmd, ioc_status);
+               break;
        case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
        case MPI2_IOCSTATUS_INVALID_FUNCTION:
        case MPI2_IOCSTATUS_INVALID_SGL:
@@ -5503,6 +5618,9 @@ scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_add_shost_fail;
        }
 
+       scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
+           | SHOST_DIF_TYPE3_PROTECTION);
+
        /* event thread */
        snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
            "fw_event%d", ioc->id);