From patchwork Fri Feb 3 12:59:14 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Sahrawat X-Patchwork-Id: 139364 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 460A3104796 for ; Fri, 3 Feb 2012 23:55:26 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753848Ab2BCMzY (ORCPT ); Fri, 3 Feb 2012 07:55:24 -0500 Received: from mail-pw0-f46.google.com ([209.85.160.46]:51151 "EHLO mail-pw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753276Ab2BCMzX (ORCPT ); Fri, 3 Feb 2012 07:55:23 -0500 Received: by pbdu11 with SMTP id u11so2879020pbd.19 for ; Fri, 03 Feb 2012 04:55:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; bh=iUGcAQ5e9eyaJla5zcR/1ii6WrVl7nyFaZ0djBwa0Ms=; b=YkjwJYTTjdaIMRYo5VRaE9cWwKP4F0dA9gFHPWkjgJxCDVLHSdvkePoywNWiKLGDDf M/p2fC9YEs8tb+DvlfzdQcaNJDjBNkU2KD2Wia86f4dRST59xFDeTCwn0+XjAVAXh+PN AaXp/eywbtpYXKs2HZCP+dem/L+nUleWJOk5I= Received: by 10.68.220.162 with SMTP id px2mr17332600pbc.76.1328273723004; Fri, 03 Feb 2012 04:55:23 -0800 (PST) Received: from localhost.localdomain ([125.19.39.117]) by mx.google.com with ESMTPS id t10sm12901095pbb.18.2012.02.03.04.55.18 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 03 Feb 2012 04:55:22 -0800 (PST) From: Amit Sahrawat To: Jeff Garzik , "James E.J. Bottomley" Cc: Nam-Jae Jeon , Amit Sahrawat , linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org, Amit Sahrawat Subject: [PATCH 1/1] scsi: retrieve cache mode using ATA_16 if normal routine fails Date: Fri, 3 Feb 2012 18:29:14 +0530 Message-Id: <1328273954-5010-1-git-send-email-amit.sahrawat83@gmail.com> X-Mailer: git-send-email 1.7.2.3 Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org It has been observed that a number of USB HDD's do not respond correctly to SCSI mode sense command(retrieve caching pages) which results in their Write Cache being discarded by queue requests i.e., WCE if left set to '0'(disabled). This results in a number of Filesystem corruptions, when the device is unplugged abruptly. So, in order to identify the devices correctly - give it a last try using ATA_16 after failure from normal routine. Signed-off-by: Amit Sahrawat Signed-off-by: Namjae Jeon --- drivers/ata/libata-scsi.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sd.c | 17 +++++++++++++++ include/linux/libata.h | 3 ++ 3 files changed, 71 insertions(+), 0 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 508a60b..d5b00e6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -562,6 +562,57 @@ error: } /** + * ata_get_cachestatus - Handler for to get WriteCache Status + * using ATA_16 scsi command + * @scsidev: Device to which we are issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * '0' for Write Cache Disabled and on any error. + * '1' for Write Cache enabled + */ +int ata_get_cachestatus(struct scsi_device *scsidev) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE] = {0}; + u8 *sensebuf = NULL, *argbuf = NULL; + enum dma_data_direction data_dir; + + sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); + if (!sensebuf) + return rc; + + argbuf = kmalloc(ATA_SECT_SIZE, GFP_KERNEL); + if (argbuf == NULL) + goto error; + + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (4 << 1); /* PIO Data-in */ + scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, + block count in sector count field */ + data_dir = DMA_FROM_DEVICE; + scsi_cmd[14] = ATA_IDENTIFY_DEV; + + if (!scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, ATA_SECT_SIZE, + sensebuf, (10*HZ), 5, 0, NULL)) { + /* + * '6th' Bit in Word 85 Corresponds to Write Cache + * being Enabled/disabled, Word 85 represnets the + * features supported + */ + if (le16_to_cpu(((unsigned short *)argbuf)[85]) & 0x20) + rc = 1; + } + +error: + kfree(sensebuf); + kfree(argbuf); + return rc; +} + +/** * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl * @scsidev: Device to which we are issuing command * @arg: User provided data for issuing command diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c691fb5..a6b887d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -50,6 +50,11 @@ #include #include #include + +#ifdef CONFIG_ATA +#include +#endif + #include #include #include @@ -2129,7 +2134,11 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (modepage == 0x3F) { sd_printk(KERN_ERR, sdkp, "No Caching mode page " "present\n"); +#ifdef CONFIG_ATA + goto WCE_USING_ATA; +#else goto defaults; +#endif } else if ((buffer[offset] & 0x3f) != modepage) { sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); goto defaults; @@ -2149,6 +2158,14 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) "Uses READ/WRITE(6), disabling FUA\n"); sdkp->DPOFUA = 0; } +#ifdef CONFIG_ATA +WCE_USING_ATA: + if (!sdp->removable && !sdkp->WCE) { + sd_printk(KERN_NOTICE, sdkp, "Try to check write cache " + "enable/disable using ATA command\n"); + sdkp->WCE = ata_get_cachestatus(sdp); + } +#endif if (sdkp->first_scan || old_wce != sdkp->WCE || old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA) diff --git a/include/linux/libata.h b/include/linux/libata.h index cafc09a..33fc73f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -84,6 +84,8 @@ } \ }) +#define ATA_IDENTIFY_DEV 0xEC + /* NEW: debug levels */ #define HAVE_LIBATA_MSG 1 @@ -990,6 +992,7 @@ extern void ata_host_init(struct ata_host *, struct device *, unsigned long, struct ata_port_operations *); extern int ata_scsi_detect(struct scsi_host_template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); +extern int ata_get_cachestatus(struct scsi_device *scsidev); extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd); extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev, int cmd, void __user *arg);