mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
[SCSI] isci: T10 DIF support
This allows the controller to do WRITE_INSERT and READ_STRIP for SAS disks that support protection information. SAS disks must be formatted with protection information to use this feature via sg_format. sg3_utils-1.32 -- sg_format version 1.19 20110730 sg_format usage: sg_format --format --verbose --pinfo /dev/sda Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
a6fe35c052
commit
3d2d752549
@ -528,6 +528,13 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
|
||||
goto err_host_alloc;
|
||||
}
|
||||
pci_info->hosts[i] = h;
|
||||
|
||||
/* turn on DIF support */
|
||||
scsi_host_set_prot(h->shost,
|
||||
SHOST_DIF_TYPE1_PROTECTION |
|
||||
SHOST_DIF_TYPE2_PROTECTION |
|
||||
SHOST_DIF_TYPE3_PROTECTION);
|
||||
scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
|
||||
}
|
||||
|
||||
err = isci_setup_interrupts(pdev);
|
||||
|
@ -53,6 +53,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include "isci.h"
|
||||
#include "task.h"
|
||||
#include "request.h"
|
||||
@ -264,6 +265,141 @@ static void scu_ssp_reqeust_construct_task_context(
|
||||
task_context->response_iu_lower = lower_32_bits(dma_addr);
|
||||
}
|
||||
|
||||
static u8 scu_bg_blk_size(struct scsi_device *sdp)
|
||||
{
|
||||
switch (sdp->sector_size) {
|
||||
case 512:
|
||||
return 0;
|
||||
case 1024:
|
||||
return 1;
|
||||
case 4096:
|
||||
return 3;
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 scu_dif_bytes(u32 len, u32 sector_size)
|
||||
{
|
||||
return (len >> ilog2(sector_size)) * 8;
|
||||
}
|
||||
|
||||
static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
|
||||
{
|
||||
struct scu_task_context *tc = ireq->tc;
|
||||
struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
|
||||
u8 blk_sz = scu_bg_blk_size(scmd->device);
|
||||
|
||||
tc->block_guard_enable = 1;
|
||||
tc->blk_prot_en = 1;
|
||||
tc->blk_sz = blk_sz;
|
||||
/* DIF write insert */
|
||||
tc->blk_prot_func = 0x2;
|
||||
|
||||
tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
|
||||
scmd->device->sector_size);
|
||||
|
||||
/* always init to 0, used by hw */
|
||||
tc->interm_crc_val = 0;
|
||||
|
||||
tc->init_crc_seed = 0;
|
||||
tc->app_tag_verify = 0;
|
||||
tc->app_tag_gen = 0;
|
||||
tc->ref_tag_seed_verify = 0;
|
||||
|
||||
/* always init to same as bg_blk_sz */
|
||||
tc->UD_bytes_immed_val = scmd->device->sector_size;
|
||||
|
||||
tc->reserved_DC_0 = 0;
|
||||
|
||||
/* always init to 8 */
|
||||
tc->DIF_bytes_immed_val = 8;
|
||||
|
||||
tc->reserved_DC_1 = 0;
|
||||
tc->bgc_blk_sz = scmd->device->sector_size;
|
||||
tc->reserved_E0_0 = 0;
|
||||
tc->app_tag_gen_mask = 0;
|
||||
|
||||
/** setup block guard control **/
|
||||
tc->bgctl = 0;
|
||||
|
||||
/* DIF write insert */
|
||||
tc->bgctl_f.op = 0x2;
|
||||
|
||||
tc->app_tag_verify_mask = 0;
|
||||
|
||||
/* must init to 0 for hw */
|
||||
tc->blk_guard_err = 0;
|
||||
|
||||
tc->reserved_E8_0 = 0;
|
||||
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
|
||||
tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff;
|
||||
else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->ref_tag_seed_gen = 0;
|
||||
}
|
||||
|
||||
static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
|
||||
{
|
||||
struct scu_task_context *tc = ireq->tc;
|
||||
struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
|
||||
u8 blk_sz = scu_bg_blk_size(scmd->device);
|
||||
|
||||
tc->block_guard_enable = 1;
|
||||
tc->blk_prot_en = 1;
|
||||
tc->blk_sz = blk_sz;
|
||||
/* DIF read strip */
|
||||
tc->blk_prot_func = 0x1;
|
||||
|
||||
tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
|
||||
scmd->device->sector_size);
|
||||
|
||||
/* always init to 0, used by hw */
|
||||
tc->interm_crc_val = 0;
|
||||
|
||||
tc->init_crc_seed = 0;
|
||||
tc->app_tag_verify = 0;
|
||||
tc->app_tag_gen = 0;
|
||||
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
|
||||
tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff;
|
||||
else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->ref_tag_seed_verify = 0;
|
||||
|
||||
/* always init to same as bg_blk_sz */
|
||||
tc->UD_bytes_immed_val = scmd->device->sector_size;
|
||||
|
||||
tc->reserved_DC_0 = 0;
|
||||
|
||||
/* always init to 8 */
|
||||
tc->DIF_bytes_immed_val = 8;
|
||||
|
||||
tc->reserved_DC_1 = 0;
|
||||
tc->bgc_blk_sz = scmd->device->sector_size;
|
||||
tc->reserved_E0_0 = 0;
|
||||
tc->app_tag_gen_mask = 0;
|
||||
|
||||
/** setup block guard control **/
|
||||
tc->bgctl = 0;
|
||||
|
||||
/* DIF read strip */
|
||||
tc->bgctl_f.crc_verify = 1;
|
||||
tc->bgctl_f.op = 0x1;
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
|
||||
tc->bgctl_f.ref_tag_chk = 1;
|
||||
tc->bgctl_f.app_f_detect = 1;
|
||||
} else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->bgctl_f.app_ref_f_detect = 1;
|
||||
|
||||
tc->app_tag_verify_mask = 0;
|
||||
|
||||
/* must init to 0 for hw */
|
||||
tc->blk_guard_err = 0;
|
||||
|
||||
tc->reserved_E8_0 = 0;
|
||||
tc->ref_tag_seed_gen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is will fill in the SCU Task Context for a SSP IO request.
|
||||
* @sci_req:
|
||||
@ -274,6 +410,10 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
|
||||
u32 len)
|
||||
{
|
||||
struct scu_task_context *task_context = ireq->tc;
|
||||
struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
|
||||
struct scsi_cmnd *scmd = sas_task->uldd_task;
|
||||
u8 prot_type = scsi_get_prot_type(scmd);
|
||||
u8 prot_op = scsi_get_prot_op(scmd);
|
||||
|
||||
scu_ssp_reqeust_construct_task_context(ireq, task_context);
|
||||
|
||||
@ -296,6 +436,13 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
|
||||
|
||||
if (task_context->transfer_length_bytes > 0)
|
||||
sci_request_build_sgl(ireq);
|
||||
|
||||
if (prot_type != SCSI_PROT_DIF_TYPE0) {
|
||||
if (prot_op == SCSI_PROT_READ_STRIP)
|
||||
scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
|
||||
else if (prot_op == SCSI_PROT_WRITE_INSERT)
|
||||
scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -866,9 +866,9 @@ struct scu_task_context {
|
||||
struct transport_snapshot snapshot; /* read only set to 0 */
|
||||
|
||||
/* OFFSET 0x5C */
|
||||
u32 block_protection_enable:1;
|
||||
u32 block_size:2;
|
||||
u32 block_protection_function:2;
|
||||
u32 blk_prot_en:1;
|
||||
u32 blk_sz:2;
|
||||
u32 blk_prot_func:2;
|
||||
u32 reserved_5C_0:9;
|
||||
u32 active_sgl_element:2; /* read only set to 0 */
|
||||
u32 sgl_exhausted:1; /* read only set to 0 */
|
||||
@ -896,33 +896,56 @@ struct scu_task_context {
|
||||
u32 reserved_C4_CC[3];
|
||||
|
||||
/* OFFSET 0xD0 */
|
||||
u32 intermediate_crc_value:16;
|
||||
u32 initial_crc_seed:16;
|
||||
u32 interm_crc_val:16;
|
||||
u32 init_crc_seed:16;
|
||||
|
||||
/* OFFSET 0xD4 */
|
||||
u32 application_tag_for_verify:16;
|
||||
u32 application_tag_for_generate:16;
|
||||
u32 app_tag_verify:16;
|
||||
u32 app_tag_gen:16;
|
||||
|
||||
/* OFFSET 0xD8 */
|
||||
u32 reference_tag_seed_for_verify_function;
|
||||
u32 ref_tag_seed_verify;
|
||||
|
||||
/* OFFSET 0xDC */
|
||||
u32 reserved_DC;
|
||||
u32 UD_bytes_immed_val:13;
|
||||
u32 reserved_DC_0:3;
|
||||
u32 DIF_bytes_immed_val:4;
|
||||
u32 reserved_DC_1:12;
|
||||
|
||||
/* OFFSET 0xE0 */
|
||||
u32 reserved_E0_0:16;
|
||||
u32 application_tag_mask_for_generate:16;
|
||||
u32 bgc_blk_sz:13;
|
||||
u32 reserved_E0_0:3;
|
||||
u32 app_tag_gen_mask:16;
|
||||
|
||||
/* OFFSET 0xE4 */
|
||||
u32 block_protection_control:16;
|
||||
u32 application_tag_mask_for_verify:16;
|
||||
union {
|
||||
u16 bgctl;
|
||||
struct {
|
||||
u16 crc_verify:1;
|
||||
u16 app_tag_chk:1;
|
||||
u16 ref_tag_chk:1;
|
||||
u16 op:2;
|
||||
u16 legacy:1;
|
||||
u16 invert_crc_seed:1;
|
||||
u16 ref_tag_gen:1;
|
||||
u16 fixed_ref_tag:1;
|
||||
u16 invert_crc:1;
|
||||
u16 app_ref_f_detect:1;
|
||||
u16 uninit_dif_check_err:1;
|
||||
u16 uninit_dif_bypass:1;
|
||||
u16 app_f_detect:1;
|
||||
u16 reserved_0:2;
|
||||
} bgctl_f;
|
||||
};
|
||||
|
||||
u16 app_tag_verify_mask;
|
||||
|
||||
/* OFFSET 0xE8 */
|
||||
u32 block_protection_error:8;
|
||||
u32 blk_guard_err:8;
|
||||
u32 reserved_E8_0:24;
|
||||
|
||||
/* OFFSET 0xEC */
|
||||
u32 reference_tag_seed_for_verify;
|
||||
u32 ref_tag_seed_gen;
|
||||
|
||||
/* OFFSET 0xF0 */
|
||||
u32 intermediate_crc_valid_snapshot:16;
|
||||
@ -937,6 +960,6 @@ struct scu_task_context {
|
||||
/* OFFSET 0xFC */
|
||||
u32 reference_tag_seed_for_generate_function_snapshot;
|
||||
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#endif /* _SCU_TASK_CONTEXT_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user