From patchwork Sat Apr 25 14:33:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Akinobu Mita X-Patchwork-Id: 6274671 Return-Path: X-Original-To: patchwork-linux-scsi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 2A3D59F313 for ; Sat, 25 Apr 2015 14:34:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EDD992022A for ; Sat, 25 Apr 2015 14:34:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AA0C1201CD for ; Sat, 25 Apr 2015 14:34:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932392AbbDYOeH (ORCPT ); Sat, 25 Apr 2015 10:34:07 -0400 Received: from mail-pd0-f173.google.com ([209.85.192.173]:33739 "EHLO mail-pd0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932210AbbDYOeE (ORCPT ); Sat, 25 Apr 2015 10:34:04 -0400 Received: by pdbnk13 with SMTP id nk13so77688378pdb.0; Sat, 25 Apr 2015 07:34:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=nFzANZJXpgG6rq5izzk0rQKBP6IkoWSw/TavyS5tt00=; b=VavXWNTNbCnIx5AD70G2Y/ypo0p9yz1InQPKGgDpPX0szHyuIag9rYuklxCQAgitQG yqyUY4DMhLb/Ge3nGgPLe3B3MOVu51EerDNH/Jv6vB0S1ZHl9eRDLvAOgk9AKiSWfX9O t5JQMk9VZ9h4xl/dybhffQRESbeQOiROPBD5+rkNAhS3dgauiD04Sl/sk9zxDvZQukxT Pq4hvRHtElYMqgUccWVKpTxWPOXY8JmnQv7WMB8OgE43YXCgrigkAOda9PILGRkQanXU BCFCzfpnoILiP0lLW0Ls/P8CxLVNSC15KqJ92Bne5TcC13HyRMAjG7+BDkNjwQVdT4NU rx7w== X-Received: by 10.66.102.99 with SMTP id fn3mr6648493pab.118.1429972444310; Sat, 25 Apr 2015 07:34:04 -0700 (PDT) Received: from localhost.localdomain (KD106168100169.ppp-bb.dion.ne.jp. [106.168.100.169]) by mx.google.com with ESMTPSA id ts4sm14156224pbc.41.2015.04.25.07.33.58 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 25 Apr 2015 07:34:03 -0700 (PDT) From: Akinobu Mita To: target-devel@vger.kernel.org Cc: Akinobu Mita , Tim Chen , Herbert Xu , "David S. Miller" , linux-crypto@vger.kernel.org, Nicholas Bellinger , Sagi Grimberg , "Martin K. Petersen" , Christoph Hellwig , "James E.J. Bottomley" , linux-scsi@vger.kernel.org Subject: [PATCH v3 3/5] target: handle odd SG mapping for data transfer memory Date: Sat, 25 Apr 2015 23:33:28 +0900 Message-Id: <1429972410-7146-4-git-send-email-akinobu.mita@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1429972410-7146-1-git-send-email-akinobu.mita@gmail.com> References: <1429972410-7146-1-git-send-email-akinobu.mita@gmail.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP sbc_dif_generate() and sbc_dif_verify() currently assume that each SG element for data transfer memory doesn't straddle the block size boundary. However, when using SG_IO ioctl, we can choose the data transfer memory which doesn't satisfy that alignment requirement. In order to handle such cases correctly, this change inverts the outer loop to iterate data transfer memory and the inner loop to iterate protection information and enables to calculate CRC for a block which straddles multiple SG elements. Signed-off-by: Akinobu Mita Cc: Tim Chen Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Cc: linux-scsi@vger.kernel.org --- * Changes from v2: - Handle odd SG mapping correctly instead of giving up drivers/target/target_core_sbc.c | 108 +++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index edba39f..33d2426 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1182,27 +1182,43 @@ sbc_dif_generate(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg, *psg = cmd->t_prot_sg; + struct scatterlist *dsg = cmd->t_data_sg, *psg; sector_t sector = cmd->t_task_lba; void *daddr, *paddr; int i, j, offset = 0; + unsigned int block_size = dev->dev_attrib.block_size; - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { paddr = kmap_atomic(sg_page(psg)) + psg->offset; + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { + for (j = 0; j < psg->length; + j += sizeof(struct se_dif_v1_tuple)) { + __u16 crc = 0; + unsigned int avail; - if (offset >= psg->length) { - kunmap_atomic(paddr); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - offset = 0; + if (offset >= dsg->length) { + offset -= dsg->length; + kunmap_atomic(daddr); + dsg = sg_next(dsg); + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; } - sdt = paddr + offset; - sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j, - dev->dev_attrib.block_size)); + sdt = paddr + j; + + avail = min(block_size, dsg->length - offset); + crc = crc_t10dif(daddr + offset, avail); + if (avail < block_size) { + kunmap_atomic(daddr); + dsg = sg_next(dsg); + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + offset = block_size - avail; + crc = crc_t10dif_update(crc, daddr, offset); + } else { + offset += block_size; + } + + sdt->guard_tag = cpu_to_be16(crc); if (cmd->prot_type == TARGET_DIF_TYPE1_PROT) sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); sdt->app_tag = 0; @@ -1215,26 +1231,23 @@ sbc_dif_generate(struct se_cmd *cmd) be32_to_cpu(sdt->ref_tag)); sector++; - offset += sizeof(struct se_dif_v1_tuple); } - kunmap_atomic(paddr); kunmap_atomic(daddr); + kunmap_atomic(paddr); } } static sense_reason_t sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt, - const void *p, sector_t sector, unsigned int ei_lba) + __u16 crc, sector_t sector, unsigned int ei_lba) { - struct se_device *dev = cmd->se_dev; - int block_size = dev->dev_attrib.block_size; __be16 csum; if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD)) goto check_ref; - csum = cpu_to_be16(crc_t10dif(p, block_size)); + csum = cpu_to_be16(crc); if (sdt->guard_tag != csum) { pr_err("DIFv1 checksum failed on sector %llu guard tag 0x%04x" @@ -1316,26 +1329,32 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg; + struct scatterlist *dsg = cmd->t_data_sg; sector_t sector = start; void *daddr, *paddr; - int i, j; + int i; sense_reason_t rc; + int dsg_off = 0; + unsigned int block_size = dev->dev_attrib.block_size; - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + for (; psg && sector < start + sectors; psg = sg_next(psg)) { paddr = kmap_atomic(sg_page(psg)) + psg->offset; + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - - if (psg_off >= psg->length) { - kunmap_atomic(paddr - psg->offset); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - psg_off = 0; + for (i = psg_off; i < psg->length && + sector < start + sectors; + i += sizeof(struct se_dif_v1_tuple)) { + __u16 crc; + unsigned int avail; + + if (dsg_off >= dsg->length) { + dsg_off -= dsg->length; + kunmap_atomic(daddr); + dsg = sg_next(dsg); + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; } - sdt = paddr + psg_off; + sdt = paddr + i; pr_debug("DIF READ sector: %llu guard_tag: 0x%04x" " app_tag: 0x%04x ref_tag: %u\n", @@ -1343,27 +1362,38 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, sdt->app_tag, be32_to_cpu(sdt->ref_tag)); if (sdt->app_tag == cpu_to_be16(0xffff)) { - sector++; - psg_off += sizeof(struct se_dif_v1_tuple); - continue; + dsg_off += block_size; + goto next; + } + + avail = min(block_size, dsg->length - dsg_off); + + crc = crc_t10dif(daddr + dsg_off, avail); + if (avail < block_size) { + kunmap_atomic(daddr); + dsg = sg_next(dsg); + daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; + dsg_off = block_size - avail; + crc = crc_t10dif_update(crc, daddr, dsg_off); + } else { + dsg_off += block_size; } - rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector, - ei_lba); + rc = sbc_dif_v1_verify(cmd, sdt, crc, sector, ei_lba); if (rc) { - kunmap_atomic(paddr - psg->offset); kunmap_atomic(daddr - dsg->offset); + kunmap_atomic(paddr - psg->offset); cmd->bad_sector = sector; return rc; } - +next: sector++; ei_lba++; - psg_off += sizeof(struct se_dif_v1_tuple); } - kunmap_atomic(paddr - psg->offset); + psg_off = 0; kunmap_atomic(daddr - dsg->offset); + kunmap_atomic(paddr - psg->offset); } return 0;