2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Adaptec AAC series RAID controller driver
|
2008-10-27 23:16:36 +08:00
|
|
|
* (c) Copyright 2001 Red Hat Inc.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* based on the old aacraid driver that is..
|
|
|
|
* Adaptec aacraid device driver for Linux.
|
|
|
|
*
|
2011-03-17 17:10:32 +08:00
|
|
|
* Copyright (c) 2000-2010 Adaptec, Inc.
|
|
|
|
* 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/completion.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <asm/uaccess.h>
|
2008-01-12 03:46:44 +08:00
|
|
|
#include <linux/highmem.h> /* For flush_kernel_dcache_page */
|
2011-05-27 21:47:43 +08:00
|
|
|
#include <linux/module.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <scsi/scsi.h>
|
|
|
|
#include <scsi/scsi_cmnd.h>
|
|
|
|
#include <scsi/scsi_device.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
|
|
|
|
|
|
|
#include "aacraid.h"
|
|
|
|
|
|
|
|
/* values for inqd_pdt: Peripheral device type in plain English */
|
|
|
|
#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */
|
|
|
|
#define INQD_PDT_PROC 0x03 /* Processor device */
|
|
|
|
#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */
|
|
|
|
#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */
|
|
|
|
#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */
|
|
|
|
#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */
|
|
|
|
|
|
|
|
#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */
|
|
|
|
#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sense codes
|
|
|
|
*/
|
2008-01-16 23:39:06 +08:00
|
|
|
|
|
|
|
#define SENCODE_NO_SENSE 0x00
|
|
|
|
#define SENCODE_END_OF_DATA 0x00
|
|
|
|
#define SENCODE_BECOMING_READY 0x04
|
|
|
|
#define SENCODE_INIT_CMD_REQUIRED 0x04
|
|
|
|
#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A
|
|
|
|
#define SENCODE_INVALID_COMMAND 0x20
|
|
|
|
#define SENCODE_LBA_OUT_OF_RANGE 0x21
|
|
|
|
#define SENCODE_INVALID_CDB_FIELD 0x24
|
|
|
|
#define SENCODE_LUN_NOT_SUPPORTED 0x25
|
|
|
|
#define SENCODE_INVALID_PARAM_FIELD 0x26
|
|
|
|
#define SENCODE_PARAM_NOT_SUPPORTED 0x26
|
|
|
|
#define SENCODE_PARAM_VALUE_INVALID 0x26
|
|
|
|
#define SENCODE_RESET_OCCURRED 0x29
|
|
|
|
#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E
|
|
|
|
#define SENCODE_INQUIRY_DATA_CHANGED 0x3F
|
|
|
|
#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39
|
|
|
|
#define SENCODE_DIAGNOSTIC_FAILURE 0x40
|
|
|
|
#define SENCODE_INTERNAL_TARGET_FAILURE 0x44
|
|
|
|
#define SENCODE_INVALID_MESSAGE_ERROR 0x49
|
|
|
|
#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c
|
|
|
|
#define SENCODE_OVERLAPPED_COMMAND 0x4E
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Additional sense codes
|
|
|
|
*/
|
2008-01-16 23:39:06 +08:00
|
|
|
|
|
|
|
#define ASENCODE_NO_SENSE 0x00
|
|
|
|
#define ASENCODE_END_OF_DATA 0x05
|
|
|
|
#define ASENCODE_BECOMING_READY 0x01
|
|
|
|
#define ASENCODE_INIT_CMD_REQUIRED 0x02
|
|
|
|
#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00
|
|
|
|
#define ASENCODE_INVALID_COMMAND 0x00
|
|
|
|
#define ASENCODE_LBA_OUT_OF_RANGE 0x00
|
|
|
|
#define ASENCODE_INVALID_CDB_FIELD 0x00
|
|
|
|
#define ASENCODE_LUN_NOT_SUPPORTED 0x00
|
|
|
|
#define ASENCODE_INVALID_PARAM_FIELD 0x00
|
|
|
|
#define ASENCODE_PARAM_NOT_SUPPORTED 0x01
|
|
|
|
#define ASENCODE_PARAM_VALUE_INVALID 0x02
|
|
|
|
#define ASENCODE_RESET_OCCURRED 0x00
|
|
|
|
#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00
|
|
|
|
#define ASENCODE_INQUIRY_DATA_CHANGED 0x03
|
|
|
|
#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00
|
|
|
|
#define ASENCODE_DIAGNOSTIC_FAILURE 0x80
|
|
|
|
#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00
|
|
|
|
#define ASENCODE_INVALID_MESSAGE_ERROR 0x00
|
|
|
|
#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00
|
|
|
|
#define ASENCODE_OVERLAPPED_COMMAND 0x00
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#define BYTE0(x) (unsigned char)(x)
|
|
|
|
#define BYTE1(x) (unsigned char)((x) >> 8)
|
|
|
|
#define BYTE2(x) (unsigned char)((x) >> 16)
|
|
|
|
#define BYTE3(x) (unsigned char)((x) >> 24)
|
|
|
|
|
2015-03-26 22:41:24 +08:00
|
|
|
/* MODE_SENSE data format */
|
|
|
|
typedef struct {
|
|
|
|
struct {
|
|
|
|
u8 data_length;
|
|
|
|
u8 med_type;
|
|
|
|
u8 dev_par;
|
|
|
|
u8 bd_length;
|
|
|
|
} __attribute__((packed)) hd;
|
|
|
|
struct {
|
|
|
|
u8 dens_code;
|
|
|
|
u8 block_count[3];
|
|
|
|
u8 reserved;
|
|
|
|
u8 block_length[3];
|
|
|
|
} __attribute__((packed)) bd;
|
|
|
|
u8 mpc_buf[3];
|
|
|
|
} __attribute__((packed)) aac_modep_data;
|
|
|
|
|
|
|
|
/* MODE_SENSE_10 data format */
|
|
|
|
typedef struct {
|
|
|
|
struct {
|
|
|
|
u8 data_length[2];
|
|
|
|
u8 med_type;
|
|
|
|
u8 dev_par;
|
|
|
|
u8 rsrvd[2];
|
|
|
|
u8 bd_length[2];
|
|
|
|
} __attribute__((packed)) hd;
|
|
|
|
struct {
|
|
|
|
u8 dens_code;
|
|
|
|
u8 block_count[3];
|
|
|
|
u8 reserved;
|
|
|
|
u8 block_length[3];
|
|
|
|
} __attribute__((packed)) bd;
|
|
|
|
u8 mpc_buf[3];
|
|
|
|
} __attribute__((packed)) aac_modep10_data;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*------------------------------------------------------------------------------
|
|
|
|
* S T R U C T S / T Y P E D E F S
|
|
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
/* SCSI inquiry data */
|
|
|
|
struct inquiry_data {
|
2008-01-16 23:39:06 +08:00
|
|
|
u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */
|
|
|
|
u8 inqd_dtq; /* RMB | Device Type Qualifier */
|
2005-04-17 06:20:36 +08:00
|
|
|
u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */
|
|
|
|
u8 inqd_rdf; /* AENC | TrmIOP | Response data format */
|
|
|
|
u8 inqd_len; /* Additional length (n-4) */
|
|
|
|
u8 inqd_pad1[2];/* Reserved - must be zero */
|
|
|
|
u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */
|
|
|
|
u8 inqd_vid[8]; /* Vendor ID */
|
|
|
|
u8 inqd_pid[16];/* Product ID */
|
|
|
|
u8 inqd_prl[4]; /* Product Revision Level */
|
|
|
|
};
|
|
|
|
|
2015-03-26 22:41:26 +08:00
|
|
|
/* Added for VPD 0x83 */
|
|
|
|
typedef struct {
|
|
|
|
u8 CodeSet:4; /* VPD_CODE_SET */
|
|
|
|
u8 Reserved:4;
|
|
|
|
u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */
|
|
|
|
u8 Reserved2:4;
|
|
|
|
u8 Reserved3;
|
|
|
|
u8 IdentifierLength;
|
|
|
|
u8 VendId[8];
|
|
|
|
u8 ProductId[16];
|
|
|
|
u8 SerialNumber[8]; /* SN in ASCII */
|
|
|
|
|
|
|
|
} TVPD_ID_Descriptor_Type_1;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
u8 CodeSet:4; /* VPD_CODE_SET */
|
|
|
|
u8 Reserved:4;
|
|
|
|
u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */
|
|
|
|
u8 Reserved2:4;
|
|
|
|
u8 Reserved3;
|
|
|
|
u8 IdentifierLength;
|
|
|
|
struct TEU64Id {
|
|
|
|
u32 Serial;
|
|
|
|
/* The serial number supposed to be 40 bits,
|
|
|
|
* bit we only support 32, so make the last byte zero. */
|
|
|
|
u8 Reserved;
|
|
|
|
u8 VendId[3];
|
|
|
|
} EU64Id;
|
|
|
|
|
|
|
|
} TVPD_ID_Descriptor_Type_2;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
u8 DeviceType:5;
|
|
|
|
u8 DeviceTypeQualifier:3;
|
|
|
|
u8 PageCode;
|
|
|
|
u8 Reserved;
|
|
|
|
u8 PageLength;
|
|
|
|
TVPD_ID_Descriptor_Type_1 IdDescriptorType1;
|
|
|
|
TVPD_ID_Descriptor_Type_2 IdDescriptorType2;
|
|
|
|
|
|
|
|
} TVPD_Page83;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* M O D U L E G L O B A L S
|
|
|
|
*/
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap);
|
|
|
|
static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg);
|
|
|
|
static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg);
|
|
|
|
static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
|
|
|
|
struct aac_raw_io2 *rio2, int sg_max);
|
|
|
|
static int aac_convert_sgraw2(struct aac_raw_io2 *rio2,
|
|
|
|
int pages, int nseg, int nseg_new);
|
2005-04-17 06:20:36 +08:00
|
|
|
static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
|
|
|
|
#ifdef AAC_DETAILED_STATUS_INFO
|
|
|
|
static char *aac_get_status_string(u32 status);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Non dasd selection is handled entirely in aachba now
|
2008-01-16 23:39:06 +08:00
|
|
|
*/
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int nondasd = -1;
|
2009-04-01 22:16:08 +08:00
|
|
|
static int aac_cache = 2; /* WCE=0 to avoid performance problems */
|
2005-04-17 06:20:36 +08:00
|
|
|
static int dacmode = -1;
|
2008-02-08 21:48:22 +08:00
|
|
|
int aac_msi;
|
2007-05-22 21:32:29 +08:00
|
|
|
int aac_commit = -1;
|
2006-05-11 00:12:48 +08:00
|
|
|
int startup_timeout = 180;
|
|
|
|
int aif_timeout = 120;
|
2012-02-09 14:51:04 +08:00
|
|
|
int aac_sync_mode; /* Only Sync. transfer - disabled */
|
2012-07-14 20:48:51 +08:00
|
|
|
int aac_convert_sgl = 1; /* convert non-conformable s/g list - enabled */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-02-09 14:51:04 +08:00
|
|
|
module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
|
|
|
|
" 0=off, 1=on");
|
2012-07-14 20:48:51 +08:00
|
|
|
module_param(aac_convert_sgl, int, S_IRUGO|S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(aac_convert_sgl, "Convert non-conformable s/g list"
|
|
|
|
" 0=off, 1=on");
|
2006-03-28 01:44:37 +08:00
|
|
|
module_param(nondasd, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
|
|
|
|
" 0=off, 1=on");
|
2008-01-09 04:01:07 +08:00
|
|
|
module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n"
|
|
|
|
"\tbit 0 - Disable FUA in WRITE SCSI commands\n"
|
|
|
|
"\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n"
|
2009-04-01 22:16:08 +08:00
|
|
|
"\tbit 2 - Disable only if Battery is protecting Cache");
|
2006-03-28 01:44:37 +08:00
|
|
|
module_param(dacmode, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC."
|
|
|
|
" 0=off, 1=on");
|
2007-05-22 21:32:29 +08:00
|
|
|
module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
|
|
|
|
" adapter for foreign arrays.\n"
|
|
|
|
"This is typically needed in systems that do not have a BIOS."
|
|
|
|
" 0=off, 1=on");
|
|
|
|
module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(msi, "IRQ handling."
|
2015-08-28 18:38:35 +08:00
|
|
|
" 0=PIC(default), 1=MSI, 2=MSI-X)");
|
2006-05-11 00:12:48 +08:00
|
|
|
module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
|
|
|
|
" adapter to have it's kernel up and\n"
|
|
|
|
"running. This is typically adjusted for large systems that do not"
|
|
|
|
" have a BIOS.");
|
2006-05-11 00:12:48 +08:00
|
|
|
module_param(aif_timeout, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for"
|
|
|
|
" applications to pick up AIFs before\n"
|
|
|
|
"deregistering them. This is typically adjusted for heavily burdened"
|
|
|
|
" systems.");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-17 09:28:42 +08:00
|
|
|
int numacb = -1;
|
|
|
|
module_param(numacb, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control"
|
|
|
|
" blocks (FIB) allocated. Valid values are 512 and down. Default is"
|
|
|
|
" to use suggestion from Firmware.");
|
2005-05-17 09:28:42 +08:00
|
|
|
|
|
|
|
int acbsize = -1;
|
|
|
|
module_param(acbsize, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)"
|
|
|
|
" size. Valid values are 512, 2048, 4096 and 8192. Default is to use"
|
|
|
|
" suggestion from Firmware.");
|
2006-09-19 23:59:43 +08:00
|
|
|
|
2007-06-12 21:33:54 +08:00
|
|
|
int update_interval = 30 * 60;
|
|
|
|
module_param(update_interval, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync"
|
|
|
|
" updates issued to adapter.");
|
2007-06-12 21:33:54 +08:00
|
|
|
|
|
|
|
int check_interval = 24 * 60 * 60;
|
|
|
|
module_param(check_interval, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health"
|
|
|
|
" checks.");
|
2007-06-12 21:33:54 +08:00
|
|
|
|
2007-08-11 05:50:30 +08:00
|
|
|
int aac_check_reset = 1;
|
|
|
|
module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
|
2008-04-16 20:43:00 +08:00
|
|
|
MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the"
|
2008-02-08 21:48:22 +08:00
|
|
|
" adapter. a value of -1 forces the reset to adapters programmed to"
|
|
|
|
" ignore it.");
|
2007-06-12 21:33:54 +08:00
|
|
|
|
2007-01-27 01:23:32 +08:00
|
|
|
int expose_physicals = -1;
|
2006-09-19 23:59:43 +08:00
|
|
|
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
|
2008-02-08 21:48:22 +08:00
|
|
|
MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays."
|
|
|
|
" -1=protect 0=off, 1=on");
|
2007-03-16 01:27:45 +08:00
|
|
|
|
2008-02-08 21:48:22 +08:00
|
|
|
int aac_reset_devices;
|
2007-05-22 21:32:29 +08:00
|
|
|
module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization.");
|
2007-03-16 01:27:45 +08:00
|
|
|
|
2009-04-01 22:16:08 +08:00
|
|
|
int aac_wwn = 1;
|
|
|
|
module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR);
|
|
|
|
MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n"
|
|
|
|
"\t0 - Disable\n"
|
|
|
|
"\t1 - Array Meta Data Signature (default)\n"
|
|
|
|
"\t2 - Adapter Serial Number");
|
|
|
|
|
|
|
|
|
2007-03-16 01:27:45 +08:00
|
|
|
static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
|
|
|
|
struct fib *fibptr) {
|
|
|
|
struct scsi_device *device;
|
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
|
2007-07-27 02:20:02 +08:00
|
|
|
dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
|
2008-01-16 23:39:06 +08:00
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-03-16 01:27:45 +08:00
|
|
|
scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
|
|
|
|
device = scsicmd->device;
|
|
|
|
if (unlikely(!device || !scsi_device_online(device))) {
|
|
|
|
dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* aac_get_config_status - check the adapter configuration
|
|
|
|
* @common: adapter to query
|
|
|
|
*
|
|
|
|
* Query config status, and commit the configuration if needed.
|
|
|
|
*/
|
2006-08-03 23:03:30 +08:00
|
|
|
int aac_get_config_status(struct aac_dev *dev, int commit_flag)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
struct fib * fibptr;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(fibptr = aac_fib_alloc(dev)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct aac_get_config_status *dinfo;
|
|
|
|
dinfo = (struct aac_get_config_status *) fib_data(fibptr);
|
|
|
|
|
|
|
|
dinfo->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
|
|
|
|
dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
|
|
|
|
}
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2005-04-17 06:20:36 +08:00
|
|
|
fibptr,
|
|
|
|
sizeof (struct aac_get_config_status),
|
|
|
|
FsaNormal,
|
|
|
|
1, 1,
|
|
|
|
NULL, NULL);
|
2008-01-16 23:39:06 +08:00
|
|
|
if (status < 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
|
|
|
|
} else {
|
|
|
|
struct aac_get_config_status_resp *reply
|
|
|
|
= (struct aac_get_config_status_resp *) fib_data(fibptr);
|
|
|
|
dprintk((KERN_WARNING
|
|
|
|
"aac_get_config_status: response=%d status=%d action=%d\n",
|
|
|
|
le32_to_cpu(reply->response),
|
|
|
|
le32_to_cpu(reply->status),
|
|
|
|
le32_to_cpu(reply->data.action)));
|
|
|
|
if ((le32_to_cpu(reply->response) != ST_OK) ||
|
|
|
|
(le32_to_cpu(reply->status) != CT_OK) ||
|
|
|
|
(le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
|
|
|
|
printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
|
|
|
|
status = -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
2009-12-21 21:09:27 +08:00
|
|
|
/* Do not set XferState to zero unless receives a response from F/W */
|
|
|
|
if (status >= 0)
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
|
|
|
|
if (status >= 0) {
|
2007-05-22 21:32:29 +08:00
|
|
|
if ((aac_commit == 1) || commit_flag) {
|
2005-04-17 06:20:36 +08:00
|
|
|
struct aac_commit_config * dinfo;
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo = (struct aac_commit_config *) fib_data(fibptr);
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2005-04-17 06:20:36 +08:00
|
|
|
fibptr,
|
|
|
|
sizeof (struct aac_commit_config),
|
|
|
|
FsaNormal,
|
|
|
|
1, 1,
|
|
|
|
NULL, NULL);
|
2009-12-21 21:09:27 +08:00
|
|
|
/* Do not set XferState to zero unless
|
|
|
|
* receives a response from F/W */
|
|
|
|
if (status >= 0)
|
|
|
|
aac_fib_complete(fibptr);
|
2007-05-22 21:32:29 +08:00
|
|
|
} else if (aac_commit == 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_WARNING
|
|
|
|
"aac_get_config_status: Foreign device configurations are being ignored\n");
|
|
|
|
}
|
|
|
|
}
|
2009-12-21 21:09:27 +08:00
|
|
|
/* FIB should be freed only after getting the response from the F/W */
|
|
|
|
if (status != -ERESTARTSYS)
|
|
|
|
aac_fib_free(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2010-05-10 19:12:28 +08:00
|
|
|
static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
|
|
|
|
{
|
|
|
|
char inq_data;
|
|
|
|
scsi_sg_copy_to_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
|
|
|
if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
|
|
|
|
inq_data &= 0xdf;
|
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* aac_get_containers - list containers
|
|
|
|
* @common: adapter to probe
|
|
|
|
*
|
|
|
|
* Make a list of all containers on this controller
|
|
|
|
*/
|
|
|
|
int aac_get_containers(struct aac_dev *dev)
|
|
|
|
{
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr;
|
2008-01-16 23:39:06 +08:00
|
|
|
u32 index;
|
2005-04-17 06:20:36 +08:00
|
|
|
int status = 0;
|
|
|
|
struct fib * fibptr;
|
|
|
|
struct aac_get_container_count *dinfo;
|
|
|
|
struct aac_get_container_count_resp *dresp;
|
|
|
|
int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(fibptr = aac_fib_alloc(dev)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo = (struct aac_get_container_count *) fib_data(fibptr);
|
|
|
|
dinfo->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2005-04-17 06:20:36 +08:00
|
|
|
fibptr,
|
|
|
|
sizeof (struct aac_get_container_count),
|
|
|
|
FsaNormal,
|
|
|
|
1, 1,
|
|
|
|
NULL, NULL);
|
|
|
|
if (status >= 0) {
|
|
|
|
dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
|
|
|
|
maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
|
2015-03-26 22:41:27 +08:00
|
|
|
if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_SUPPORTED_240_VOLUMES) {
|
|
|
|
maximum_num_containers =
|
|
|
|
le32_to_cpu(dresp->MaxSimpleVolumes);
|
|
|
|
}
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-12-21 21:09:27 +08:00
|
|
|
/* FIB should be freed only after getting the response from the F/W */
|
|
|
|
if (status != -ERESTARTSYS)
|
|
|
|
aac_fib_free(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
|
|
|
|
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
|
2007-06-12 04:17:55 +08:00
|
|
|
fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
|
2007-03-16 03:55:07 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (!fsa_dev_ptr)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
dev->fsa_dev = fsa_dev_ptr;
|
|
|
|
dev->maximum_num_containers = maximum_num_containers;
|
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
for (index = 0; index < dev->maximum_num_containers; ) {
|
2005-04-17 06:20:36 +08:00
|
|
|
fsa_dev_ptr[index].devname[0] = '\0';
|
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
status = aac_probe_container(dev, index);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
if (status < 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
|
|
|
|
break;
|
|
|
|
}
|
2005-09-23 00:15:24 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* If there are no more containers, then stop asking.
|
|
|
|
*/
|
2007-03-16 03:55:07 +08:00
|
|
|
if (++index >= status)
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_container_name_callback(void *context, struct fib * fibptr)
|
|
|
|
{
|
|
|
|
struct aac_get_name_resp * get_name_reply;
|
|
|
|
struct scsi_cmnd * scsicmd;
|
|
|
|
|
|
|
|
scsicmd = (struct scsi_cmnd *) context;
|
|
|
|
|
2007-03-16 01:27:45 +08:00
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
|
2006-06-23 17:06:06 +08:00
|
|
|
BUG_ON(fibptr == NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
|
|
|
|
/* Failure is irrelevant, using default value instead */
|
|
|
|
if ((le32_to_cpu(get_name_reply->status) == CT_OK)
|
|
|
|
&& (get_name_reply->data[0] != '\0')) {
|
2005-08-16 01:50:24 +08:00
|
|
|
char *sp = get_name_reply->data;
|
2015-03-26 22:41:24 +08:00
|
|
|
sp[sizeof(((struct aac_get_name_resp *)NULL)->data)] = '\0';
|
2005-04-17 06:20:36 +08:00
|
|
|
while (*sp == ' ')
|
|
|
|
++sp;
|
2005-08-16 01:50:24 +08:00
|
|
|
if (*sp) {
|
2008-03-09 12:44:34 +08:00
|
|
|
struct inquiry_data inq;
|
2005-08-16 01:50:24 +08:00
|
|
|
char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)];
|
|
|
|
int count = sizeof(d);
|
|
|
|
char *dp = d;
|
|
|
|
do {
|
|
|
|
*dp++ = (*sp) ? *sp++ : ' ';
|
|
|
|
} while (--count > 0);
|
2008-03-09 12:44:34 +08:00
|
|
|
|
|
|
|
scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq));
|
|
|
|
memcpy(inq.inqd_pid, d, sizeof(d));
|
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq));
|
2005-08-16 01:50:24 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2005-08-16 01:50:24 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
2005-10-25 01:52:22 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aac_get_container_name - get container name, none blocking.
|
|
|
|
*/
|
2007-03-16 01:26:55 +08:00
|
|
|
static int aac_get_container_name(struct scsi_cmnd * scsicmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct aac_get_name *dinfo;
|
|
|
|
struct fib * cmd_fibcontext;
|
|
|
|
struct aac_dev * dev;
|
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(dev)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
|
|
|
|
|
|
|
|
dinfo->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
dinfo->type = cpu_to_le32(CT_READ_NAME);
|
2007-03-16 01:26:55 +08:00
|
|
|
dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2008-01-16 23:39:06 +08:00
|
|
|
cmd_fibcontext,
|
2015-08-28 18:38:33 +08:00
|
|
|
sizeof(struct aac_get_name_resp),
|
2008-01-16 23:39:06 +08:00
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback)get_container_name_callback,
|
2005-04-17 06:20:36 +08:00
|
|
|
(void *) scsicmd);
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2006-03-28 01:43:40 +08:00
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
2006-03-28 01:43:40 +08:00
|
|
|
}
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
|
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-03-16 03:55:07 +08:00
|
|
|
struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
|
2007-03-16 03:55:07 +08:00
|
|
|
return aac_scsi_cmd(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
scsicmd->result = DID_NO_CONNECT << 16;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
static void _aac_probe_container2(void * context, struct fib * fibptr)
|
2007-03-16 03:55:07 +08:00
|
|
|
{
|
2007-03-16 01:27:45 +08:00
|
|
|
struct fsa_dev_info *fsa_dev_ptr;
|
2007-03-16 03:55:07 +08:00
|
|
|
int (*callback)(struct scsi_cmnd *);
|
2007-03-16 01:27:45 +08:00
|
|
|
struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
|
|
|
|
|
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
2007-03-16 03:55:07 +08:00
|
|
|
|
|
|
|
scsicmd->SCp.Status = 0;
|
2007-06-12 04:17:55 +08:00
|
|
|
fsa_dev_ptr = fibptr->dev->fsa_dev;
|
2007-03-16 03:55:07 +08:00
|
|
|
if (fsa_dev_ptr) {
|
|
|
|
struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
|
|
|
|
fsa_dev_ptr += scmd_id(scsicmd);
|
|
|
|
|
|
|
|
if ((le32_to_cpu(dresp->status) == ST_OK) &&
|
|
|
|
(le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
|
|
|
|
(le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
|
2015-03-26 22:41:24 +08:00
|
|
|
if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_VARIABLE_BLOCK_SIZE)) {
|
|
|
|
dresp->mnt[0].fileinfo.bdevinfo.block_size = 0x200;
|
|
|
|
fsa_dev_ptr->block_size = 0x200;
|
|
|
|
} else {
|
|
|
|
fsa_dev_ptr->block_size =
|
|
|
|
le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size);
|
|
|
|
}
|
2007-03-16 03:55:07 +08:00
|
|
|
fsa_dev_ptr->valid = 1;
|
2008-05-01 04:03:42 +08:00
|
|
|
/* sense_key holds the current state of the spin-up */
|
|
|
|
if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
|
|
|
|
fsa_dev_ptr->sense_data.sense_key = NOT_READY;
|
|
|
|
else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
|
|
|
|
fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
|
2007-03-16 03:55:07 +08:00
|
|
|
fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
|
|
|
|
fsa_dev_ptr->size
|
|
|
|
= ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
|
|
|
|
(((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
|
|
|
|
fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
|
|
|
|
}
|
|
|
|
if ((fsa_dev_ptr->valid & 1) == 0)
|
|
|
|
fsa_dev_ptr->valid = 0;
|
|
|
|
scsicmd->SCp.Status = le32_to_cpu(dresp->count);
|
|
|
|
}
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
|
|
|
|
scsicmd->SCp.ptr = NULL;
|
2007-06-12 04:17:55 +08:00
|
|
|
(*callback)(scsicmd);
|
|
|
|
return;
|
2007-03-16 03:55:07 +08:00
|
|
|
}
|
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
static void _aac_probe_container1(void * context, struct fib * fibptr)
|
2007-03-16 03:55:07 +08:00
|
|
|
{
|
|
|
|
struct scsi_cmnd * scsicmd;
|
|
|
|
struct aac_mount * dresp;
|
|
|
|
struct aac_query_mount *dinfo;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
dresp = (struct aac_mount *) fib_data(fibptr);
|
2015-03-26 22:41:24 +08:00
|
|
|
if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_VARIABLE_BLOCK_SIZE))
|
|
|
|
dresp->mnt[0].capacityhigh = 0;
|
2007-03-16 03:55:07 +08:00
|
|
|
if ((le32_to_cpu(dresp->status) != ST_OK) ||
|
2007-06-12 04:17:55 +08:00
|
|
|
(le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
|
|
|
|
_aac_probe_container2(context, fibptr);
|
|
|
|
return;
|
|
|
|
}
|
2007-03-16 03:55:07 +08:00
|
|
|
scsicmd = (struct scsi_cmnd *) context;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 01:27:45 +08:00
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
2007-06-12 04:17:55 +08:00
|
|
|
return;
|
2007-03-16 01:27:45 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dinfo = (struct aac_query_mount *)fib_data(fibptr);
|
|
|
|
|
2015-03-26 22:41:24 +08:00
|
|
|
if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_VARIABLE_BLOCK_SIZE)
|
|
|
|
dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
|
|
|
|
else
|
|
|
|
dinfo->command = cpu_to_le32(VM_NameServe64);
|
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
dinfo->count = cpu_to_le32(scmd_id(scsicmd));
|
2005-04-17 06:20:36 +08:00
|
|
|
dinfo->type = cpu_to_le32(FT_FILESYS);
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2007-03-16 03:55:07 +08:00
|
|
|
fibptr,
|
|
|
|
sizeof(struct aac_query_mount),
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
2007-06-12 04:17:55 +08:00
|
|
|
_aac_probe_container2,
|
2007-03-16 03:55:07 +08:00
|
|
|
(void *) scsicmd);
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2007-06-12 04:17:55 +08:00
|
|
|
if (status == -EINPROGRESS)
|
2007-03-16 03:55:07 +08:00
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2007-06-12 04:17:55 +08:00
|
|
|
else if (status < 0) {
|
2007-03-16 03:55:07 +08:00
|
|
|
/* Inherit results from VM_NameServe, if any */
|
|
|
|
dresp->status = cpu_to_le32(ST_OK);
|
2007-06-12 04:17:55 +08:00
|
|
|
_aac_probe_container2(context, fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-03-16 03:55:07 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
|
|
|
|
{
|
|
|
|
struct fib * fibptr;
|
|
|
|
int status = -ENOMEM;
|
|
|
|
|
|
|
|
if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
|
|
|
|
struct aac_query_mount *dinfo;
|
|
|
|
|
|
|
|
aac_fib_init(fibptr);
|
|
|
|
|
|
|
|
dinfo = (struct aac_query_mount *)fib_data(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-03-26 22:41:24 +08:00
|
|
|
if (fibptr->dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_VARIABLE_BLOCK_SIZE)
|
|
|
|
dinfo->command = cpu_to_le32(VM_NameServeAllBlk);
|
|
|
|
else
|
|
|
|
dinfo->command = cpu_to_le32(VM_NameServe);
|
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
dinfo->count = cpu_to_le32(scmd_id(scsicmd));
|
2005-09-23 00:15:24 +08:00
|
|
|
dinfo->type = cpu_to_le32(FT_FILESYS);
|
2007-03-16 03:55:07 +08:00
|
|
|
scsicmd->SCp.ptr = (char *)callback;
|
2005-09-23 00:15:24 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
|
|
|
fibptr,
|
|
|
|
sizeof(struct aac_query_mount),
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
2007-06-12 04:17:55 +08:00
|
|
|
_aac_probe_container1,
|
2007-03-16 03:55:07 +08:00
|
|
|
(void *) scsicmd);
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (status < 0) {
|
|
|
|
scsicmd->SCp.ptr = NULL;
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (status < 0) {
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
|
|
|
|
if (fsa_dev_ptr) {
|
|
|
|
fsa_dev_ptr += scmd_id(scsicmd);
|
|
|
|
if ((fsa_dev_ptr->valid & 1) == 0) {
|
|
|
|
fsa_dev_ptr->valid = 0;
|
|
|
|
return (*callback)(scsicmd);
|
|
|
|
}
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-03-16 03:55:07 +08:00
|
|
|
return status;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
/**
|
|
|
|
* aac_probe_container - query a logical volume
|
|
|
|
* @dev: device to query
|
|
|
|
* @cid: container identifier
|
|
|
|
*
|
|
|
|
* Queries the controller about the given volume. The volume information
|
|
|
|
* is updated in the struct fsa_dev_info structure rather than returned.
|
|
|
|
*/
|
|
|
|
static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
|
|
|
|
{
|
|
|
|
scsicmd->device = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-03-16 03:55:07 +08:00
|
|
|
int aac_probe_container(struct aac_dev *dev, int cid)
|
|
|
|
{
|
|
|
|
struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
|
|
|
|
struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (!scsicmd || !scsidev) {
|
|
|
|
kfree(scsicmd);
|
|
|
|
kfree(scsidev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
scsicmd->list.next = NULL;
|
2007-06-12 04:17:55 +08:00
|
|
|
scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
|
2007-03-16 03:55:07 +08:00
|
|
|
|
|
|
|
scsicmd->device = scsidev;
|
|
|
|
scsidev->sdev_state = 0;
|
|
|
|
scsidev->id = cid;
|
|
|
|
scsidev->host = dev->scsi_host_ptr;
|
|
|
|
|
|
|
|
if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
|
|
|
|
while (scsicmd->device == scsidev)
|
|
|
|
schedule();
|
2007-03-22 01:49:47 +08:00
|
|
|
kfree(scsidev);
|
2007-03-16 03:55:07 +08:00
|
|
|
status = scsicmd->SCp.Status;
|
|
|
|
kfree(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Local Structure to set SCSI inquiry data strings */
|
|
|
|
struct scsi_inq {
|
|
|
|
char vid[8]; /* Vendor ID */
|
|
|
|
char pid[16]; /* Product ID */
|
|
|
|
char prl[4]; /* Product Revision Level */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* InqStrCopy - string merge
|
|
|
|
* @a: string to copy from
|
|
|
|
* @b: string to copy to
|
|
|
|
*
|
2008-01-16 23:39:06 +08:00
|
|
|
* Copy a String from one location to another
|
2005-04-17 06:20:36 +08:00
|
|
|
* without copying \0
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void inqstrcpy(char *a, char *b)
|
|
|
|
{
|
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
while (*a != (char)0)
|
2005-04-17 06:20:36 +08:00
|
|
|
*b++ = *a++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *container_types[] = {
|
2008-01-16 23:39:06 +08:00
|
|
|
"None",
|
|
|
|
"Volume",
|
|
|
|
"Mirror",
|
|
|
|
"Stripe",
|
|
|
|
"RAID5",
|
|
|
|
"SSRW",
|
|
|
|
"SSRO",
|
|
|
|
"Morph",
|
|
|
|
"Legacy",
|
|
|
|
"RAID4",
|
|
|
|
"RAID10",
|
|
|
|
"RAID00",
|
|
|
|
"V-MIRRORS",
|
|
|
|
"PSEUDO R4",
|
2005-04-17 06:20:36 +08:00
|
|
|
"RAID50",
|
2005-06-21 02:55:24 +08:00
|
|
|
"RAID5D",
|
|
|
|
"RAID5D0",
|
|
|
|
"RAID1E",
|
|
|
|
"RAID6",
|
|
|
|
"RAID60",
|
2008-01-16 23:39:06 +08:00
|
|
|
"Unknown"
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2008-01-09 04:23:49 +08:00
|
|
|
char * get_container_type(unsigned tindex)
|
|
|
|
{
|
|
|
|
if (tindex >= ARRAY_SIZE(container_types))
|
|
|
|
tindex = ARRAY_SIZE(container_types) - 1;
|
|
|
|
return container_types[tindex];
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Function: setinqstr
|
|
|
|
*
|
|
|
|
* Arguments: [1] pointer to void [1] int
|
|
|
|
*
|
|
|
|
* Purpose: Sets SCSI inquiry data strings for vendor, product
|
2011-03-31 09:57:33 +08:00
|
|
|
* and revision level. Allows strings to be set in platform dependent
|
|
|
|
* files instead of in OS dependent driver source.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
2005-10-25 01:51:53 +08:00
|
|
|
static void setinqstr(struct aac_dev *dev, void *data, int tindex)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct scsi_inq *str;
|
|
|
|
|
|
|
|
str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
|
2005-10-25 01:51:53 +08:00
|
|
|
memset(str, ' ', sizeof(*str));
|
|
|
|
|
|
|
|
if (dev->supplement_adapter_info.AdapterTypeText[0]) {
|
|
|
|
char * cp = dev->supplement_adapter_info.AdapterTypeText;
|
2008-01-12 05:46:24 +08:00
|
|
|
int c;
|
|
|
|
if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
|
|
|
|
inqstrcpy("SMC", str->vid);
|
|
|
|
else {
|
|
|
|
c = sizeof(str->vid);
|
|
|
|
while (*cp && *cp != ' ' && --c)
|
|
|
|
++cp;
|
|
|
|
c = *cp;
|
|
|
|
*cp = '\0';
|
|
|
|
inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
|
|
|
|
str->vid);
|
|
|
|
*cp = c;
|
|
|
|
while (*cp && *cp != ' ')
|
|
|
|
++cp;
|
|
|
|
}
|
2005-10-25 01:51:53 +08:00
|
|
|
while (*cp == ' ')
|
|
|
|
++cp;
|
|
|
|
/* last six chars reserved for vol type */
|
|
|
|
c = 0;
|
|
|
|
if (strlen(cp) > sizeof(str->pid)) {
|
|
|
|
c = cp[sizeof(str->pid)];
|
|
|
|
cp[sizeof(str->pid)] = '\0';
|
|
|
|
}
|
|
|
|
inqstrcpy (cp, str->pid);
|
|
|
|
if (c)
|
|
|
|
cp[sizeof(str->pid)] = c;
|
|
|
|
} else {
|
|
|
|
struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
|
2006-06-09 13:23:48 +08:00
|
|
|
|
|
|
|
inqstrcpy (mp->vname, str->vid);
|
2005-10-25 01:51:53 +08:00
|
|
|
/* last six chars reserved for vol type */
|
|
|
|
inqstrcpy (mp->model, str->pid);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-09 13:23:48 +08:00
|
|
|
if (tindex < ARRAY_SIZE(container_types)){
|
2005-04-17 06:20:36 +08:00
|
|
|
char *findit = str->pid;
|
|
|
|
|
|
|
|
for ( ; *findit != ' '; findit++); /* walk till we find a space */
|
|
|
|
/* RAID is superfluous in the context of a RAID device */
|
|
|
|
if (memcmp(findit-4, "RAID", 4) == 0)
|
|
|
|
*(findit -= 4) = ' ';
|
2005-10-25 01:51:53 +08:00
|
|
|
if (((findit - str->pid) + strlen(container_types[tindex]))
|
|
|
|
< (sizeof(str->pid) + sizeof(str->prl)))
|
|
|
|
inqstrcpy (container_types[tindex], findit + 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
inqstrcpy ("V1.0", str->prl);
|
|
|
|
}
|
|
|
|
|
2007-07-18 02:01:28 +08:00
|
|
|
static void get_container_serial_callback(void *context, struct fib * fibptr)
|
|
|
|
{
|
|
|
|
struct aac_get_serial_resp * get_serial_reply;
|
|
|
|
struct scsi_cmnd * scsicmd;
|
|
|
|
|
|
|
|
BUG_ON(fibptr == NULL);
|
|
|
|
|
|
|
|
scsicmd = (struct scsi_cmnd *) context;
|
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
|
|
|
get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
|
|
|
|
/* Failure is irrelevant, using default value instead */
|
|
|
|
if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
|
2015-03-26 22:41:26 +08:00
|
|
|
/*Check to see if it's for VPD 0x83 or 0x80 */
|
|
|
|
if (scsicmd->cmnd[2] == 0x83) {
|
|
|
|
/* vpd page 0x83 - Device Identification Page */
|
|
|
|
int i;
|
|
|
|
TVPD_Page83 VPDPage83Data;
|
|
|
|
|
|
|
|
memset(((u8 *)&VPDPage83Data), 0,
|
|
|
|
sizeof(VPDPage83Data));
|
|
|
|
|
|
|
|
/* DIRECT_ACCESS_DEVIC */
|
|
|
|
VPDPage83Data.DeviceType = 0;
|
|
|
|
/* DEVICE_CONNECTED */
|
|
|
|
VPDPage83Data.DeviceTypeQualifier = 0;
|
|
|
|
/* VPD_DEVICE_IDENTIFIERS */
|
|
|
|
VPDPage83Data.PageCode = 0x83;
|
|
|
|
VPDPage83Data.Reserved = 0;
|
|
|
|
VPDPage83Data.PageLength =
|
|
|
|
sizeof(VPDPage83Data.IdDescriptorType1) +
|
|
|
|
sizeof(VPDPage83Data.IdDescriptorType2);
|
|
|
|
|
|
|
|
/* T10 Vendor Identifier Field Format */
|
|
|
|
/* VpdCodeSetAscii */
|
|
|
|
VPDPage83Data.IdDescriptorType1.CodeSet = 2;
|
|
|
|
/* VpdIdentifierTypeVendorId */
|
|
|
|
VPDPage83Data.IdDescriptorType1.IdentifierType = 1;
|
|
|
|
VPDPage83Data.IdDescriptorType1.IdentifierLength =
|
|
|
|
sizeof(VPDPage83Data.IdDescriptorType1) - 4;
|
|
|
|
|
|
|
|
/* "ADAPTEC " for adaptec */
|
|
|
|
memcpy(VPDPage83Data.IdDescriptorType1.VendId,
|
|
|
|
"ADAPTEC ",
|
|
|
|
sizeof(VPDPage83Data.IdDescriptorType1.VendId));
|
|
|
|
memcpy(VPDPage83Data.IdDescriptorType1.ProductId,
|
|
|
|
"ARRAY ",
|
|
|
|
sizeof(
|
|
|
|
VPDPage83Data.IdDescriptorType1.ProductId));
|
|
|
|
|
|
|
|
/* Convert to ascii based serial number.
|
|
|
|
* The LSB is the the end.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
u8 temp =
|
|
|
|
(u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF);
|
|
|
|
if (temp > 0x9) {
|
|
|
|
VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
|
|
|
|
'A' + (temp - 0xA);
|
|
|
|
} else {
|
|
|
|
VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
|
|
|
|
'0' + temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* VpdCodeSetBinary */
|
|
|
|
VPDPage83Data.IdDescriptorType2.CodeSet = 1;
|
|
|
|
/* VpdIdentifierTypeEUI64 */
|
|
|
|
VPDPage83Data.IdDescriptorType2.IdentifierType = 2;
|
|
|
|
VPDPage83Data.IdDescriptorType2.IdentifierLength =
|
|
|
|
sizeof(VPDPage83Data.IdDescriptorType2) - 4;
|
|
|
|
|
|
|
|
VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0;
|
|
|
|
VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0;
|
|
|
|
VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0;
|
|
|
|
|
|
|
|
VPDPage83Data.IdDescriptorType2.EU64Id.Serial =
|
|
|
|
get_serial_reply->uid;
|
|
|
|
VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0;
|
|
|
|
|
|
|
|
/* Move the inquiry data to the response buffer. */
|
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data,
|
|
|
|
sizeof(VPDPage83Data));
|
|
|
|
} else {
|
|
|
|
/* It must be for VPD 0x80 */
|
|
|
|
char sp[13];
|
|
|
|
/* EVPD bit set */
|
|
|
|
sp[0] = INQD_PDT_DA;
|
|
|
|
sp[1] = scsicmd->cmnd[2];
|
|
|
|
sp[2] = 0;
|
|
|
|
sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
|
|
|
|
le32_to_cpu(get_serial_reply->uid));
|
|
|
|
scsi_sg_copy_from_buffer(scsicmd, sp,
|
|
|
|
sizeof(sp));
|
|
|
|
}
|
2007-07-18 02:01:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aac_get_container_serial - get container serial, none blocking.
|
|
|
|
*/
|
|
|
|
static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct aac_get_serial *dinfo;
|
|
|
|
struct fib * cmd_fibcontext;
|
|
|
|
struct aac_dev * dev;
|
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
|
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(dev)))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
aac_fib_init(cmd_fibcontext);
|
|
|
|
dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
|
|
|
|
|
|
|
|
dinfo->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
|
|
|
|
dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
|
|
|
|
|
|
|
|
status = aac_fib_send(ContainerCommand,
|
|
|
|
cmd_fibcontext,
|
2015-08-28 18:38:33 +08:00
|
|
|
sizeof(struct aac_get_serial_resp),
|
2007-07-18 02:01:28 +08:00
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) get_container_serial_callback,
|
|
|
|
(void *) scsicmd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
|
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function: setinqserial
|
|
|
|
*
|
|
|
|
* Arguments: [1] pointer to void [1] int
|
|
|
|
*
|
|
|
|
* Purpose: Sets SCSI Unit Serial number.
|
|
|
|
* This is a fake. We should read a proper
|
|
|
|
* serial number from the container. <SuSE>But
|
|
|
|
* without docs it's quite hard to do it :-)
|
|
|
|
* So this will have to do in the meantime.</SuSE>
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int setinqserial(struct aac_dev *dev, void *data, int cid)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This breaks array migration.
|
|
|
|
*/
|
|
|
|
return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
|
|
|
|
le32_to_cpu(dev->adapter_info.serial[0]), cid);
|
|
|
|
}
|
|
|
|
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
static inline void set_sense(struct sense_data *sense_data, u8 sense_key,
|
|
|
|
u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
u8 *sense_buf = (u8 *)sense_data;
|
|
|
|
/* Sense data valid, err code 70h */
|
|
|
|
sense_buf[0] = 0x70; /* No info field */
|
2005-04-17 06:20:36 +08:00
|
|
|
sense_buf[1] = 0; /* Segment number, always zero */
|
|
|
|
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
sense_buf[2] = sense_key; /* Sense key */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
sense_buf[12] = sense_code; /* Additional sense code */
|
|
|
|
sense_buf[13] = a_sense_code; /* Additional sense code qualifier */
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sense_key == ILLEGAL_REQUEST) {
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
sense_buf[7] = 10; /* Additional sense length */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
sense_buf[15] = bit_pointer;
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Illegal parameter is in the parameter block */
|
|
|
|
if (sense_code == SENCODE_INVALID_CDB_FIELD)
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
sense_buf[15] |= 0xc0;/* Std sense key specific field */
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Illegal parameter is in the CDB block */
|
|
|
|
sense_buf[16] = field_pointer >> 8; /* MSB */
|
|
|
|
sense_buf[17] = field_pointer; /* LSB */
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
} else
|
|
|
|
sense_buf[7] = 6; /* Additional sense length */
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
|
|
|
|
{
|
|
|
|
if (lba & 0xffffffff00000000LL) {
|
|
|
|
int cid = scmd_id(cmd);
|
|
|
|
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
|
|
|
|
cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
|
|
|
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
2007-01-24 07:00:30 +08:00
|
|
|
memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
2008-01-14 23:25:33 +08:00
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2007-01-24 07:00:30 +08:00
|
|
|
cmd->scsi_done(cmd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void io_callback(void *context, struct fib * fibptr);
|
|
|
|
|
|
|
|
static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
|
|
|
|
{
|
2012-07-14 20:48:51 +08:00
|
|
|
struct aac_dev *dev = fib->dev;
|
|
|
|
u16 fibsize, command;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
2012-07-14 20:48:51 +08:00
|
|
|
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
|
|
|
|
struct aac_raw_io2 *readcmd2;
|
|
|
|
readcmd2 = (struct aac_raw_io2 *) fib_data(fib);
|
|
|
|
memset(readcmd2, 0, sizeof(struct aac_raw_io2));
|
|
|
|
readcmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
readcmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
|
2015-03-26 22:41:24 +08:00
|
|
|
readcmd2->byteCount = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2012-07-14 20:48:51 +08:00
|
|
|
readcmd2->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ);
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sgraw2(cmd, readcmd2,
|
|
|
|
dev->scsi_host_ptr->sg_tablesize);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
command = ContainerRawIo2;
|
|
|
|
fibsize = sizeof(struct aac_raw_io2) +
|
|
|
|
((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
|
|
|
|
} else {
|
|
|
|
struct aac_raw_io *readcmd;
|
|
|
|
readcmd = (struct aac_raw_io *) fib_data(fib);
|
|
|
|
readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
|
2015-03-26 22:41:24 +08:00
|
|
|
readcmd->count = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2012-07-14 20:48:51 +08:00
|
|
|
readcmd->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
readcmd->flags = cpu_to_le16(RIO_TYPE_READ);
|
|
|
|
readcmd->bpTotal = 0;
|
|
|
|
readcmd->bpComplete = 0;
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sgraw(cmd, &readcmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
command = ContainerRawIo;
|
|
|
|
fibsize = sizeof(struct aac_raw_io) +
|
|
|
|
((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw));
|
|
|
|
}
|
2007-01-24 07:00:30 +08:00
|
|
|
|
|
|
|
BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
2012-07-14 20:48:51 +08:00
|
|
|
return aac_fib_send(command,
|
2007-01-24 07:00:30 +08:00
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
|
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_read64 *readcmd;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
|
|
|
readcmd = (struct aac_read64 *) fib_data(fib);
|
|
|
|
readcmd->command = cpu_to_le32(VM_CtHostRead64);
|
|
|
|
readcmd->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
readcmd->sector_count = cpu_to_le16(count);
|
|
|
|
readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
readcmd->pad = 0;
|
|
|
|
readcmd->flags = 0;
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg64(cmd, &readcmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
fibsize = sizeof(struct aac_read64) +
|
|
|
|
((le32_to_cpu(readcmd->sg.count) - 1) *
|
|
|
|
sizeof (struct sgentry64));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ContainerCommand64,
|
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
|
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_read *readcmd;
|
2015-03-26 22:41:24 +08:00
|
|
|
struct aac_dev *dev = fib->dev;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
|
|
|
readcmd = (struct aac_read *) fib_data(fib);
|
|
|
|
readcmd->command = cpu_to_le32(VM_CtBlockRead);
|
2007-11-09 01:27:47 +08:00
|
|
|
readcmd->cid = cpu_to_le32(scmd_id(cmd));
|
2007-01-24 07:00:30 +08:00
|
|
|
readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
|
2015-03-26 22:41:24 +08:00
|
|
|
readcmd->count = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2007-01-24 07:00:30 +08:00
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg(cmd, &readcmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
fibsize = sizeof(struct aac_read) +
|
|
|
|
((le32_to_cpu(readcmd->sg.count) - 1) *
|
|
|
|
sizeof (struct sgentry));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ContainerCommand,
|
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
2007-05-19 02:51:34 +08:00
|
|
|
static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
|
2007-01-24 07:00:30 +08:00
|
|
|
{
|
2012-07-14 20:48:51 +08:00
|
|
|
struct aac_dev *dev = fib->dev;
|
|
|
|
u16 fibsize, command;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
2012-07-14 20:48:51 +08:00
|
|
|
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
|
|
|
|
struct aac_raw_io2 *writecmd2;
|
|
|
|
writecmd2 = (struct aac_raw_io2 *) fib_data(fib);
|
|
|
|
memset(writecmd2, 0, sizeof(struct aac_raw_io2));
|
|
|
|
writecmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
writecmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
|
2015-03-26 22:41:24 +08:00
|
|
|
writecmd2->byteCount = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2012-07-14 20:48:51 +08:00
|
|
|
writecmd2->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
writecmd2->flags = (fua && ((aac_cache & 5) != 1) &&
|
|
|
|
(((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
|
|
|
|
cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) :
|
|
|
|
cpu_to_le16(RIO2_IO_TYPE_WRITE);
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sgraw2(cmd, writecmd2,
|
|
|
|
dev->scsi_host_ptr->sg_tablesize);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
command = ContainerRawIo2;
|
|
|
|
fibsize = sizeof(struct aac_raw_io2) +
|
|
|
|
((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
|
|
|
|
} else {
|
|
|
|
struct aac_raw_io *writecmd;
|
|
|
|
writecmd = (struct aac_raw_io *) fib_data(fib);
|
|
|
|
writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
|
2015-03-26 22:41:24 +08:00
|
|
|
writecmd->count = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2012-07-14 20:48:51 +08:00
|
|
|
writecmd->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
|
|
|
|
(((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
|
|
|
|
cpu_to_le16(RIO_TYPE_WRITE|RIO_SUREWRITE) :
|
|
|
|
cpu_to_le16(RIO_TYPE_WRITE);
|
|
|
|
writecmd->bpTotal = 0;
|
|
|
|
writecmd->bpComplete = 0;
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sgraw(cmd, &writecmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-07-14 20:48:51 +08:00
|
|
|
command = ContainerRawIo;
|
|
|
|
fibsize = sizeof(struct aac_raw_io) +
|
|
|
|
((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw));
|
|
|
|
}
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
2012-07-14 20:48:51 +08:00
|
|
|
return aac_fib_send(command,
|
2007-01-24 07:00:30 +08:00
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
2007-05-19 02:51:34 +08:00
|
|
|
static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
|
2007-01-24 07:00:30 +08:00
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_write64 *writecmd;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
|
|
|
writecmd = (struct aac_write64 *) fib_data(fib);
|
|
|
|
writecmd->command = cpu_to_le32(VM_CtHostWrite64);
|
|
|
|
writecmd->cid = cpu_to_le16(scmd_id(cmd));
|
|
|
|
writecmd->sector_count = cpu_to_le16(count);
|
|
|
|
writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
|
|
|
|
writecmd->pad = 0;
|
|
|
|
writecmd->flags = 0;
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg64(cmd, &writecmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
fibsize = sizeof(struct aac_write64) +
|
|
|
|
((le32_to_cpu(writecmd->sg.count) - 1) *
|
|
|
|
sizeof (struct sgentry64));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ContainerCommand64,
|
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
2007-05-19 02:51:34 +08:00
|
|
|
static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
|
2007-01-24 07:00:30 +08:00
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_write *writecmd;
|
2015-03-26 22:41:24 +08:00
|
|
|
struct aac_dev *dev = fib->dev;
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
aac_fib_init(fib);
|
|
|
|
writecmd = (struct aac_write *) fib_data(fib);
|
|
|
|
writecmd->command = cpu_to_le32(VM_CtBlockWrite);
|
2007-11-09 01:27:47 +08:00
|
|
|
writecmd->cid = cpu_to_le32(scmd_id(cmd));
|
2007-01-24 07:00:30 +08:00
|
|
|
writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
|
2015-03-26 22:41:24 +08:00
|
|
|
writecmd->count = cpu_to_le32(count *
|
|
|
|
dev->fsa_dev[scmd_id(cmd)].block_size);
|
2007-01-24 07:00:30 +08:00
|
|
|
writecmd->sg.count = cpu_to_le32(1);
|
|
|
|
/* ->stable is not used - it did mean which type of write */
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg(cmd, &writecmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
fibsize = sizeof(struct aac_write) +
|
|
|
|
((le32_to_cpu(writecmd->sg.count) - 1) *
|
|
|
|
sizeof (struct sgentry));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ContainerCommand,
|
|
|
|
fib,
|
|
|
|
fibsize,
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback) io_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd)
|
|
|
|
{
|
|
|
|
struct aac_srb * srbcmd;
|
|
|
|
u32 flag;
|
|
|
|
u32 timeout;
|
|
|
|
|
|
|
|
aac_fib_init(fib);
|
|
|
|
switch(cmd->sc_data_direction){
|
|
|
|
case DMA_TO_DEVICE:
|
|
|
|
flag = SRB_DataOut;
|
|
|
|
break;
|
|
|
|
case DMA_BIDIRECTIONAL:
|
|
|
|
flag = SRB_DataIn | SRB_DataOut;
|
|
|
|
break;
|
|
|
|
case DMA_FROM_DEVICE:
|
|
|
|
flag = SRB_DataIn;
|
|
|
|
break;
|
|
|
|
case DMA_NONE:
|
|
|
|
default: /* shuts up some versions of gcc */
|
|
|
|
flag = SRB_NoDataXfer;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
srbcmd = (struct aac_srb*) fib_data(fib);
|
|
|
|
srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
|
|
|
|
srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd)));
|
|
|
|
srbcmd->id = cpu_to_le32(scmd_id(cmd));
|
|
|
|
srbcmd->lun = cpu_to_le32(cmd->device->lun);
|
|
|
|
srbcmd->flags = cpu_to_le32(flag);
|
2008-09-14 20:55:09 +08:00
|
|
|
timeout = cmd->request->timeout/HZ;
|
2007-01-24 07:00:30 +08:00
|
|
|
if (timeout == 0)
|
|
|
|
timeout = 1;
|
|
|
|
srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds
|
|
|
|
srbcmd->retry_limit = 0; /* Obsolete parameter */
|
|
|
|
srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
|
|
|
|
return srbcmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void aac_srb_callback(void *context, struct fib * fibptr);
|
|
|
|
|
|
|
|
static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
|
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-05-26 01:00:42 +08:00
|
|
|
srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
|
2007-01-24 07:00:30 +08:00
|
|
|
|
|
|
|
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
|
|
|
|
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
|
|
|
|
/*
|
|
|
|
* Build Scatter/Gather list
|
|
|
|
*/
|
|
|
|
fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
|
|
|
|
((le32_to_cpu(srbcmd->sg.count) & 0xff) *
|
|
|
|
sizeof (struct sgentry64));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ScsiPortCommand64, fib,
|
|
|
|
fibsize, FsaNormal, 0, 1,
|
|
|
|
(fib_callback) aac_srb_callback,
|
|
|
|
(void *) cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
|
|
|
|
{
|
|
|
|
u16 fibsize;
|
|
|
|
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
long ret;
|
2007-01-24 07:00:30 +08:00
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2007-05-26 01:00:42 +08:00
|
|
|
srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
|
2007-01-24 07:00:30 +08:00
|
|
|
|
|
|
|
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
|
|
|
|
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
|
|
|
|
/*
|
|
|
|
* Build Scatter/Gather list
|
|
|
|
*/
|
|
|
|
fibsize = sizeof (struct aac_srb) +
|
|
|
|
(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
|
|
|
|
sizeof (struct sgentry));
|
|
|
|
BUG_ON (fibsize > (fib->dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1,
|
|
|
|
(fib_callback) aac_srb_callback, (void *) cmd);
|
|
|
|
}
|
|
|
|
|
2007-12-14 08:14:18 +08:00
|
|
|
static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
|
|
|
|
{
|
2009-04-01 22:16:08 +08:00
|
|
|
if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac &&
|
|
|
|
(fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
|
2007-12-14 08:14:18 +08:00
|
|
|
return FAILED;
|
|
|
|
return aac_scsi_32(fib, cmd);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int aac_get_adapter_info(struct aac_dev* dev)
|
|
|
|
{
|
|
|
|
struct fib* fibptr;
|
|
|
|
int rcode;
|
|
|
|
u32 tmp;
|
2005-06-21 02:55:24 +08:00
|
|
|
struct aac_adapter_info *info;
|
|
|
|
struct aac_bus_info *command;
|
|
|
|
struct aac_bus_info_response *bus_info;
|
2005-05-17 09:28:42 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(fibptr = aac_fib_alloc(dev)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-05-17 09:28:42 +08:00
|
|
|
info = (struct aac_adapter_info *) fib_data(fibptr);
|
|
|
|
memset(info,0,sizeof(*info));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
rcode = aac_fib_send(RequestAdapterInfo,
|
2008-01-16 23:39:06 +08:00
|
|
|
fibptr,
|
2005-05-17 09:28:42 +08:00
|
|
|
sizeof(*info),
|
2008-01-16 23:39:06 +08:00
|
|
|
FsaNormal,
|
2005-09-21 03:56:50 +08:00
|
|
|
-1, 1, /* First `interrupt' command uses special wait */
|
2008-01-16 23:39:06 +08:00
|
|
|
NULL,
|
2005-05-17 09:28:42 +08:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (rcode < 0) {
|
2009-12-21 21:09:27 +08:00
|
|
|
/* FIB should be freed only after
|
|
|
|
* getting the response from the F/W */
|
|
|
|
if (rcode != -ERESTARTSYS) {
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
}
|
2005-05-17 09:28:42 +08:00
|
|
|
return rcode;
|
|
|
|
}
|
|
|
|
memcpy(&dev->adapter_info, info, sizeof(*info));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-17 09:28:42 +08:00
|
|
|
if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
|
2008-01-09 04:32:00 +08:00
|
|
|
struct aac_supplement_adapter_info * sinfo;
|
2005-05-17 09:28:42 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-05-17 09:28:42 +08:00
|
|
|
|
2008-01-09 04:32:00 +08:00
|
|
|
sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
|
2005-05-17 09:28:42 +08:00
|
|
|
|
2008-01-09 04:32:00 +08:00
|
|
|
memset(sinfo,0,sizeof(*sinfo));
|
2005-05-17 09:28:42 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
rcode = aac_fib_send(RequestSupplementAdapterInfo,
|
2005-05-17 09:28:42 +08:00
|
|
|
fibptr,
|
2008-01-09 04:32:00 +08:00
|
|
|
sizeof(*sinfo),
|
2005-05-17 09:28:42 +08:00
|
|
|
FsaNormal,
|
|
|
|
1, 1,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (rcode >= 0)
|
2008-01-09 04:32:00 +08:00
|
|
|
memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
|
2009-12-21 21:09:27 +08:00
|
|
|
if (rcode == -ERESTARTSYS) {
|
|
|
|
fibptr = aac_fib_alloc(dev);
|
|
|
|
if (!fibptr)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2005-05-17 09:28:42 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-06-21 02:55:24 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
/*
|
|
|
|
* GetBusInfo
|
2005-06-21 02:55:24 +08:00
|
|
|
*/
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(fibptr);
|
2005-06-21 02:55:24 +08:00
|
|
|
|
|
|
|
bus_info = (struct aac_bus_info_response *) fib_data(fibptr);
|
|
|
|
|
|
|
|
memset(bus_info, 0, sizeof(*bus_info));
|
|
|
|
|
|
|
|
command = (struct aac_bus_info *)bus_info;
|
|
|
|
|
|
|
|
command->Command = cpu_to_le32(VM_Ioctl);
|
|
|
|
command->ObjType = cpu_to_le32(FT_DRIVE);
|
|
|
|
command->MethodId = cpu_to_le32(1);
|
|
|
|
command->CtlCmd = cpu_to_le32(GetBusInfo);
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
rcode = aac_fib_send(ContainerCommand,
|
2005-06-21 02:55:24 +08:00
|
|
|
fibptr,
|
|
|
|
sizeof (*bus_info),
|
|
|
|
FsaNormal,
|
|
|
|
1, 1,
|
|
|
|
NULL, NULL);
|
|
|
|
|
2007-12-14 08:14:18 +08:00
|
|
|
/* reasoned default */
|
|
|
|
dev->maximum_num_physicals = 16;
|
2005-06-21 02:55:24 +08:00
|
|
|
if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
|
|
|
|
dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
|
|
|
|
dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
|
|
|
|
}
|
|
|
|
|
2006-08-03 23:03:30 +08:00
|
|
|
if (!dev->in_reset) {
|
2007-06-20 04:29:24 +08:00
|
|
|
char buffer[16];
|
2006-08-03 23:03:30 +08:00
|
|
|
tmp = le32_to_cpu(dev->adapter_info.kernelrev);
|
|
|
|
printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
|
2008-01-16 23:39:06 +08:00
|
|
|
dev->name,
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->id,
|
|
|
|
tmp>>24,
|
|
|
|
(tmp>>16)&0xff,
|
|
|
|
tmp&0xff,
|
2005-05-17 09:28:42 +08:00
|
|
|
le32_to_cpu(dev->adapter_info.kernelbuild),
|
|
|
|
(int)sizeof(dev->supplement_adapter_info.BuildDate),
|
|
|
|
dev->supplement_adapter_info.BuildDate);
|
2006-08-03 23:03:30 +08:00
|
|
|
tmp = le32_to_cpu(dev->adapter_info.monitorrev);
|
|
|
|
printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->name, dev->id,
|
|
|
|
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
|
|
|
|
le32_to_cpu(dev->adapter_info.monitorbuild));
|
2006-08-03 23:03:30 +08:00
|
|
|
tmp = le32_to_cpu(dev->adapter_info.biosrev);
|
|
|
|
printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->name, dev->id,
|
|
|
|
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
|
|
|
|
le32_to_cpu(dev->adapter_info.biosbuild));
|
2007-06-20 04:29:24 +08:00
|
|
|
buffer[0] = '\0';
|
2008-02-22 07:13:36 +08:00
|
|
|
if (aac_get_serial_number(
|
2007-06-20 04:29:24 +08:00
|
|
|
shost_to_class(dev->scsi_host_ptr), buffer))
|
|
|
|
printk(KERN_INFO "%s%d: serial %s",
|
|
|
|
dev->name, dev->id, buffer);
|
2007-03-29 01:44:54 +08:00
|
|
|
if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
|
|
|
|
printk(KERN_INFO "%s%d: TSID %.*s\n",
|
|
|
|
dev->name, dev->id,
|
|
|
|
(int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
|
|
|
|
dev->supplement_adapter_info.VpdInfo.Tsid);
|
|
|
|
}
|
2008-02-09 00:36:23 +08:00
|
|
|
if (!aac_check_reset || ((aac_check_reset == 1) &&
|
2008-01-09 04:48:25 +08:00
|
|
|
(dev->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_IGNORE_RESET))) {
|
2007-06-12 21:33:54 +08:00
|
|
|
printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
|
|
|
|
dev->name, dev->id);
|
|
|
|
}
|
2006-08-03 23:03:30 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-09 04:01:07 +08:00
|
|
|
dev->cache_protected = 0;
|
2008-01-18 01:25:07 +08:00
|
|
|
dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
|
|
|
|
AAC_FEATURE_JBOD) != 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->nondasd_support = 0;
|
|
|
|
dev->raid_scsi_mode = 0;
|
2008-01-09 04:01:07 +08:00
|
|
|
if(dev->adapter_info.options & AAC_OPT_NONDASD)
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->nondasd_support = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the firmware supports ROMB RAID/SCSI mode and we are currently
|
|
|
|
* in RAID/SCSI mode, set the flag. For now if in this mode we will
|
|
|
|
* force nondasd support on. If we decide to allow the non-dasd flag
|
|
|
|
* additional changes changes will have to be made to support
|
|
|
|
* RAID/SCSI. the function aac_scsi_cmd in this module will have to be
|
|
|
|
* changed to support the new dev->raid_scsi_mode flag instead of
|
|
|
|
* leaching off of the dev->nondasd_support flag. Also in linit.c the
|
|
|
|
* function aac_detect will have to be modified where it sets up the
|
|
|
|
* max number of channels based on the aac->nondasd_support flag only.
|
|
|
|
*/
|
|
|
|
if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
|
|
|
|
(dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
|
|
|
|
dev->nondasd_support = 1;
|
|
|
|
dev->raid_scsi_mode = 1;
|
|
|
|
}
|
|
|
|
if (dev->raid_scsi_mode != 0)
|
|
|
|
printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
|
|
|
|
dev->name, dev->id);
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2008-01-09 04:01:07 +08:00
|
|
|
if (nondasd != -1)
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->nondasd_support = (nondasd!=0);
|
2008-02-09 00:36:23 +08:00
|
|
|
if (dev->nondasd_support && !dev->in_reset)
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
|
|
|
|
|
2009-04-14 05:40:14 +08:00
|
|
|
if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32))
|
2009-04-01 22:16:08 +08:00
|
|
|
dev->needs_dac = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->dac_support = 0;
|
2009-04-01 22:16:08 +08:00
|
|
|
if ((sizeof(dma_addr_t) > 4) && dev->needs_dac &&
|
|
|
|
(dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) {
|
2008-02-09 00:36:23 +08:00
|
|
|
if (!dev->in_reset)
|
|
|
|
printk(KERN_INFO "%s%d: 64bit support enabled.\n",
|
|
|
|
dev->name, dev->id);
|
2005-04-17 06:20:36 +08:00
|
|
|
dev->dac_support = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dacmode != -1) {
|
|
|
|
dev->dac_support = (dacmode!=0);
|
|
|
|
}
|
2009-04-01 22:16:08 +08:00
|
|
|
|
|
|
|
/* avoid problems with AAC_QUIRK_SCSI_32 controllers */
|
|
|
|
if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks
|
|
|
|
& AAC_QUIRK_SCSI_32)) {
|
|
|
|
dev->nondasd_support = 0;
|
|
|
|
dev->jbod = 0;
|
|
|
|
expose_physicals = 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if(dev->dac_support != 0) {
|
2009-04-07 10:01:13 +08:00
|
|
|
if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) &&
|
|
|
|
!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) {
|
2008-02-09 00:36:23 +08:00
|
|
|
if (!dev->in_reset)
|
|
|
|
printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
|
|
|
|
dev->name, dev->id);
|
2009-04-07 10:01:15 +08:00
|
|
|
} else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) &&
|
|
|
|
!pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) {
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
|
|
|
|
dev->name, dev->id);
|
|
|
|
dev->dac_support = 0;
|
|
|
|
} else {
|
|
|
|
printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
|
|
|
|
dev->name, dev->id);
|
|
|
|
rcode = -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
2008-01-16 23:39:06 +08:00
|
|
|
/*
|
2007-01-24 07:00:30 +08:00
|
|
|
* Deal with configuring for the individualized limits of each packet
|
|
|
|
* interface.
|
2005-05-17 09:28:42 +08:00
|
|
|
*/
|
2007-01-24 07:00:30 +08:00
|
|
|
dev->a_ops.adapter_scsi = (dev->dac_support)
|
2007-12-14 08:14:18 +08:00
|
|
|
? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
|
|
|
|
? aac_scsi_32_64
|
|
|
|
: aac_scsi_64)
|
2007-01-24 07:00:30 +08:00
|
|
|
: aac_scsi_32;
|
|
|
|
if (dev->raw_io_interface) {
|
|
|
|
dev->a_ops.adapter_bounds = (dev->raw_io_64)
|
|
|
|
? aac_bounds_64
|
|
|
|
: aac_bounds_32;
|
|
|
|
dev->a_ops.adapter_read = aac_read_raw_io;
|
|
|
|
dev->a_ops.adapter_write = aac_write_raw_io;
|
|
|
|
} else {
|
|
|
|
dev->a_ops.adapter_bounds = aac_bounds_32;
|
2005-08-04 06:39:49 +08:00
|
|
|
dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
|
2005-05-17 09:28:42 +08:00
|
|
|
sizeof(struct aac_fibhdr) -
|
2005-09-21 03:57:04 +08:00
|
|
|
sizeof(struct aac_write) + sizeof(struct sgentry)) /
|
|
|
|
sizeof(struct sgentry);
|
2005-08-04 06:39:49 +08:00
|
|
|
if (dev->dac_support) {
|
2007-01-24 07:00:30 +08:00
|
|
|
dev->a_ops.adapter_read = aac_read_block64;
|
|
|
|
dev->a_ops.adapter_write = aac_write_block64;
|
2008-01-16 23:39:06 +08:00
|
|
|
/*
|
|
|
|
* 38 scatter gather elements
|
2005-08-04 06:39:49 +08:00
|
|
|
*/
|
|
|
|
dev->scsi_host_ptr->sg_tablesize =
|
|
|
|
(dev->max_fib_size -
|
|
|
|
sizeof(struct aac_fibhdr) -
|
|
|
|
sizeof(struct aac_write64) +
|
2005-09-21 03:57:04 +08:00
|
|
|
sizeof(struct sgentry64)) /
|
|
|
|
sizeof(struct sgentry64);
|
2007-01-24 07:00:30 +08:00
|
|
|
} else {
|
|
|
|
dev->a_ops.adapter_read = aac_read_block;
|
|
|
|
dev->a_ops.adapter_write = aac_write_block;
|
2005-08-04 06:39:49 +08:00
|
|
|
}
|
|
|
|
dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
|
2011-03-17 17:10:32 +08:00
|
|
|
if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
|
2005-08-04 06:39:49 +08:00
|
|
|
/*
|
|
|
|
* Worst case size that could cause sg overflow when
|
|
|
|
* we break up SG elements that are larger than 64KB.
|
|
|
|
* Would be nice if we could tell the SCSI layer what
|
|
|
|
* the maximum SG element size can be. Worst case is
|
|
|
|
* (sg_tablesize-1) 4KB elements with one 64KB
|
|
|
|
* element.
|
|
|
|
* 32bit -> 468 or 238KB 64bit -> 424 or 212KB
|
|
|
|
*/
|
|
|
|
dev->scsi_host_ptr->max_sectors =
|
|
|
|
(dev->scsi_host_ptr->sg_tablesize * 8) + 112;
|
|
|
|
}
|
2005-05-17 09:28:42 +08:00
|
|
|
}
|
2009-12-21 21:09:27 +08:00
|
|
|
/* FIB should be freed only after getting the response from the F/W */
|
|
|
|
if (rcode != -ERESTARTSYS) {
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return rcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-04 06:39:09 +08:00
|
|
|
static void io_callback(void *context, struct fib * fibptr)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct aac_dev *dev;
|
|
|
|
struct aac_read_reply *readreply;
|
|
|
|
struct scsi_cmnd *scsicmd;
|
|
|
|
u32 cid;
|
|
|
|
|
|
|
|
scsicmd = (struct scsi_cmnd *) context;
|
|
|
|
|
2007-03-16 01:27:45 +08:00
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
dev = fibptr->dev;
|
2006-03-28 01:43:25 +08:00
|
|
|
cid = scmd_id(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-09-23 00:15:24 +08:00
|
|
|
if (nblank(dprintk(x))) {
|
|
|
|
u64 lba;
|
|
|
|
switch (scsicmd->cmnd[0]) {
|
|
|
|
case WRITE_6:
|
|
|
|
case READ_6:
|
|
|
|
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
|
|
|
|
(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
|
|
|
|
break;
|
|
|
|
case WRITE_16:
|
|
|
|
case READ_16:
|
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 56) |
|
|
|
|
((u64)scsicmd->cmnd[3] << 48) |
|
|
|
|
((u64)scsicmd->cmnd[4] << 40) |
|
|
|
|
((u64)scsicmd->cmnd[5] << 32) |
|
|
|
|
((u64)scsicmd->cmnd[6] << 24) |
|
|
|
|
(scsicmd->cmnd[7] << 16) |
|
|
|
|
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
|
|
|
|
break;
|
|
|
|
case WRITE_12:
|
|
|
|
case READ_12:
|
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) |
|
|
|
|
(scsicmd->cmnd[3] << 16) |
|
|
|
|
(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) |
|
|
|
|
(scsicmd->cmnd[3] << 16) |
|
|
|
|
(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printk(KERN_DEBUG
|
|
|
|
"io_callback[cpu %d]: lba = %llu, t = %ld.\n",
|
|
|
|
smp_processor_id(), (unsigned long long)lba, jiffies);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-23 17:06:06 +08:00
|
|
|
BUG_ON(fibptr == NULL);
|
2007-05-26 01:00:42 +08:00
|
|
|
|
|
|
|
scsi_dma_unmap(scsicmd);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
readreply = (struct aac_read_reply *)fib_data(fibptr);
|
2008-05-01 04:03:42 +08:00
|
|
|
switch (le32_to_cpu(readreply->status)) {
|
|
|
|
case ST_OK:
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_GOOD;
|
|
|
|
dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
|
|
|
|
break;
|
|
|
|
case ST_NOT_READY:
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
|
|
|
|
SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
|
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
|
|
|
break;
|
|
|
|
default:
|
2005-05-17 09:28:42 +08:00
|
|
|
#ifdef AAC_DETAILED_STATUS_INFO
|
2005-08-04 06:39:09 +08:00
|
|
|
printk(KERN_WARNING "io_callback: io failed, status = %d\n",
|
2005-05-17 09:28:42 +08:00
|
|
|
le32_to_cpu(readreply->status));
|
|
|
|
#endif
|
2008-05-01 04:03:42 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
|
|
|
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
2008-01-14 23:25:33 +08:00
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2008-05-01 04:03:42 +08:00
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-25 01:52:22 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-03-16 01:26:55 +08:00
|
|
|
static int aac_read(struct scsi_cmnd * scsicmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-09-23 00:15:24 +08:00
|
|
|
u64 lba;
|
2005-04-17 06:20:36 +08:00
|
|
|
u32 count;
|
|
|
|
int status;
|
|
|
|
struct aac_dev *dev;
|
|
|
|
struct fib * cmd_fibcontext;
|
2010-05-10 19:24:01 +08:00
|
|
|
int cid;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
/*
|
|
|
|
* Get block address and transfer length
|
|
|
|
*/
|
2005-09-23 00:15:24 +08:00
|
|
|
switch (scsicmd->cmnd[0]) {
|
|
|
|
case READ_6:
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
|
2005-04-17 06:20:36 +08:00
|
|
|
count = scsicmd->cmnd[4];
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
count = 256;
|
2005-09-23 00:15:24 +08:00
|
|
|
break;
|
|
|
|
case READ_16:
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
|
2005-09-23 00:15:24 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 56) |
|
|
|
|
((u64)scsicmd->cmnd[3] << 48) |
|
2005-09-23 00:15:24 +08:00
|
|
|
((u64)scsicmd->cmnd[4] << 40) |
|
|
|
|
((u64)scsicmd->cmnd[5] << 32) |
|
2008-01-16 23:39:06 +08:00
|
|
|
((u64)scsicmd->cmnd[6] << 24) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[7] << 16) |
|
|
|
|
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
|
2008-01-16 23:39:06 +08:00
|
|
|
count = (scsicmd->cmnd[10] << 24) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[11] << 16) |
|
|
|
|
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
|
|
|
|
break;
|
|
|
|
case READ_12:
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
|
2005-09-23 00:15:24 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[3] << 16) |
|
2008-01-16 23:39:06 +08:00
|
|
|
(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
|
|
|
count = (scsicmd->cmnd[6] << 24) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[7] << 16) |
|
2008-01-16 23:39:06 +08:00
|
|
|
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
|
2005-09-23 00:15:24 +08:00
|
|
|
break;
|
|
|
|
default:
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) |
|
|
|
|
(scsicmd->cmnd[3] << 16) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
2005-04-17 06:20:36 +08:00
|
|
|
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
|
2005-09-23 00:15:24 +08:00
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2010-05-10 19:24:01 +08:00
|
|
|
|
|
|
|
if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
|
|
|
|
cid = scmd_id(scsicmd);
|
|
|
|
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
|
|
|
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-09-23 00:15:24 +08:00
|
|
|
dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
|
2005-05-17 09:28:42 +08:00
|
|
|
smp_processor_id(), (unsigned long long)lba, jiffies));
|
2007-01-24 07:00:30 +08:00
|
|
|
if (aac_adapter_bounds(dev,scsicmd,lba))
|
2005-09-23 00:15:24 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Alocate and initialize a Fib
|
|
|
|
*/
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
|
2009-12-21 21:09:27 +08:00
|
|
|
printk(KERN_WARNING "aac_read: fib allocation failed\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-01-24 07:00:30 +08:00
|
|
|
status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2006-03-28 01:43:40 +08:00
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
2006-03-28 01:43:40 +08:00
|
|
|
}
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* For some reason, the Fib didn't queue, return QUEUE_FULL
|
|
|
|
*/
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
|
2005-10-25 01:52:22 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-16 01:26:55 +08:00
|
|
|
static int aac_write(struct scsi_cmnd * scsicmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-09-23 00:15:24 +08:00
|
|
|
u64 lba;
|
2005-04-17 06:20:36 +08:00
|
|
|
u32 count;
|
2007-05-19 02:51:34 +08:00
|
|
|
int fua;
|
2005-04-17 06:20:36 +08:00
|
|
|
int status;
|
|
|
|
struct aac_dev *dev;
|
|
|
|
struct fib * cmd_fibcontext;
|
2010-05-10 19:24:01 +08:00
|
|
|
int cid;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
/*
|
|
|
|
* Get block address and transfer length
|
|
|
|
*/
|
|
|
|
if (scsicmd->cmnd[0] == WRITE_6) /* 6 byte command */
|
|
|
|
{
|
|
|
|
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
|
|
|
|
count = scsicmd->cmnd[4];
|
|
|
|
if (count == 0)
|
|
|
|
count = 256;
|
2007-05-19 02:51:34 +08:00
|
|
|
fua = 0;
|
2005-09-23 00:15:24 +08:00
|
|
|
} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
|
2005-09-23 00:15:24 +08:00
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 56) |
|
2005-09-23 00:15:24 +08:00
|
|
|
((u64)scsicmd->cmnd[3] << 48) |
|
|
|
|
((u64)scsicmd->cmnd[4] << 40) |
|
|
|
|
((u64)scsicmd->cmnd[5] << 32) |
|
2008-01-16 23:39:06 +08:00
|
|
|
((u64)scsicmd->cmnd[6] << 24) |
|
2005-09-23 00:15:24 +08:00
|
|
|
(scsicmd->cmnd[7] << 16) |
|
|
|
|
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
|
|
|
|
count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
|
|
|
|
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
|
2007-05-19 02:51:34 +08:00
|
|
|
fua = scsicmd->cmnd[1] & 0x8;
|
2005-09-23 00:15:24 +08:00
|
|
|
} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
|
2005-09-23 00:15:24 +08:00
|
|
|
|
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
|
|
|
|
| (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
|
|
|
count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
|
|
|
|
| (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
|
2007-05-19 02:51:34 +08:00
|
|
|
fua = scsicmd->cmnd[1] & 0x8;
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
2007-03-16 01:26:55 +08:00
|
|
|
dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
|
2005-09-23 00:15:24 +08:00
|
|
|
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
2005-04-17 06:20:36 +08:00
|
|
|
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
|
2007-05-19 02:51:34 +08:00
|
|
|
fua = scsicmd->cmnd[1] & 0x8;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2010-05-10 19:24:01 +08:00
|
|
|
|
|
|
|
if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
|
|
|
|
cid = scmd_id(scsicmd);
|
|
|
|
dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
|
|
|
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-09-23 00:15:24 +08:00
|
|
|
dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
smp_processor_id(), (unsigned long long)lba, jiffies));
|
2007-01-24 07:00:30 +08:00
|
|
|
if (aac_adapter_bounds(dev,scsicmd,lba))
|
2005-09-23 00:15:24 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Allocate and initialize a Fib then setup a BlockWrite command
|
|
|
|
*/
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
|
2009-12-21 21:09:27 +08:00
|
|
|
/* FIB temporarily unavailable,not catastrophic failure */
|
|
|
|
|
|
|
|
/* scsicmd->result = DID_ERROR << 16;
|
|
|
|
* scsicmd->scsi_done(scsicmd);
|
|
|
|
* return 0;
|
|
|
|
*/
|
|
|
|
printk(KERN_WARNING "aac_write: fib allocation failed\n");
|
|
|
|
return -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-05-19 02:51:34 +08:00
|
|
|
status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2006-03-28 01:43:40 +08:00
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* For some reason, the Fib didn't queue, return QUEUE_FULL
|
|
|
|
*/
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
|
2005-10-25 01:52:22 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void synchronize_callback(void *context, struct fib *fibptr)
|
|
|
|
{
|
|
|
|
struct aac_synchronize_reply *synchronizereply;
|
|
|
|
struct scsi_cmnd *cmd;
|
|
|
|
|
|
|
|
cmd = context;
|
|
|
|
|
2007-03-16 01:27:45 +08:00
|
|
|
if (!aac_valid_context(cmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
2007-07-27 21:48:49 +08:00
|
|
|
dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
smp_processor_id(), jiffies));
|
|
|
|
BUG_ON(fibptr == NULL);
|
|
|
|
|
|
|
|
|
|
|
|
synchronizereply = fib_data(fibptr);
|
|
|
|
if (le32_to_cpu(synchronizereply->status) == CT_OK)
|
2007-07-27 21:48:49 +08:00
|
|
|
cmd->result = DID_OK << 16 |
|
2005-04-17 06:20:36 +08:00
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
else {
|
|
|
|
struct scsi_device *sdev = cmd->device;
|
2007-06-12 04:17:55 +08:00
|
|
|
struct aac_dev *dev = fibptr->dev;
|
2006-03-28 01:43:25 +08:00
|
|
|
u32 cid = sdev_id(sdev);
|
2007-07-27 21:48:49 +08:00
|
|
|
printk(KERN_WARNING
|
2005-04-17 06:20:36 +08:00
|
|
|
"synchronize_callback: synchronize failed, status = %d\n",
|
|
|
|
le32_to_cpu(synchronizereply->status));
|
2007-07-27 21:48:49 +08:00
|
|
|
cmd->result = DID_OK << 16 |
|
2005-04-17 06:20:36 +08:00
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
|
|
|
|
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
2008-01-13 14:46:13 +08:00
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
2005-10-25 01:52:22 +08:00
|
|
|
cmd->scsi_done(cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-03-16 01:26:55 +08:00
|
|
|
static int aac_synchronize(struct scsi_cmnd *scsicmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct fib *cmd_fibcontext;
|
|
|
|
struct aac_synchronize *synchronizecmd;
|
|
|
|
struct scsi_cmnd *cmd;
|
|
|
|
struct scsi_device *sdev = scsicmd->device;
|
|
|
|
int active = 0;
|
2006-08-03 23:03:07 +08:00
|
|
|
struct aac_dev *aac;
|
2007-07-27 21:48:49 +08:00
|
|
|
u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
|
|
|
|
(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
|
|
|
|
u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
/*
|
2006-03-28 01:43:40 +08:00
|
|
|
* Wait for all outstanding queued commands to complete to this
|
|
|
|
* specific target (block).
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
spin_lock_irqsave(&sdev->list_lock, flags);
|
|
|
|
list_for_each_entry(cmd, &sdev->cmd_list, list)
|
2007-07-27 21:48:49 +08:00
|
|
|
if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
|
|
|
|
u64 cmnd_lba;
|
|
|
|
u32 cmnd_count;
|
|
|
|
|
|
|
|
if (cmd->cmnd[0] == WRITE_6) {
|
|
|
|
cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
|
|
|
|
(cmd->cmnd[2] << 8) |
|
|
|
|
cmd->cmnd[3];
|
|
|
|
cmnd_count = cmd->cmnd[4];
|
|
|
|
if (cmnd_count == 0)
|
|
|
|
cmnd_count = 256;
|
|
|
|
} else if (cmd->cmnd[0] == WRITE_16) {
|
|
|
|
cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
|
|
|
|
((u64)cmd->cmnd[3] << 48) |
|
|
|
|
((u64)cmd->cmnd[4] << 40) |
|
|
|
|
((u64)cmd->cmnd[5] << 32) |
|
|
|
|
((u64)cmd->cmnd[6] << 24) |
|
|
|
|
(cmd->cmnd[7] << 16) |
|
|
|
|
(cmd->cmnd[8] << 8) |
|
|
|
|
cmd->cmnd[9];
|
|
|
|
cmnd_count = (cmd->cmnd[10] << 24) |
|
|
|
|
(cmd->cmnd[11] << 16) |
|
|
|
|
(cmd->cmnd[12] << 8) |
|
|
|
|
cmd->cmnd[13];
|
|
|
|
} else if (cmd->cmnd[0] == WRITE_12) {
|
|
|
|
cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
|
|
|
|
(cmd->cmnd[3] << 16) |
|
|
|
|
(cmd->cmnd[4] << 8) |
|
|
|
|
cmd->cmnd[5];
|
|
|
|
cmnd_count = (cmd->cmnd[6] << 24) |
|
|
|
|
(cmd->cmnd[7] << 16) |
|
|
|
|
(cmd->cmnd[8] << 8) |
|
|
|
|
cmd->cmnd[9];
|
|
|
|
} else if (cmd->cmnd[0] == WRITE_10) {
|
|
|
|
cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
|
|
|
|
(cmd->cmnd[3] << 16) |
|
|
|
|
(cmd->cmnd[4] << 8) |
|
|
|
|
cmd->cmnd[5];
|
|
|
|
cmnd_count = (cmd->cmnd[7] << 8) |
|
|
|
|
cmd->cmnd[8];
|
|
|
|
} else
|
|
|
|
continue;
|
|
|
|
if (((cmnd_lba + cmnd_count) < lba) ||
|
|
|
|
(count && ((lba + count) < cmnd_lba)))
|
|
|
|
continue;
|
2005-04-17 06:20:36 +08:00
|
|
|
++active;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&sdev->list_lock, flags);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Yield the processor (requeue for later)
|
|
|
|
*/
|
|
|
|
if (active)
|
|
|
|
return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
|
|
|
2007-10-31 03:50:49 +08:00
|
|
|
aac = (struct aac_dev *)sdev->host->hostdata;
|
2006-08-03 23:03:30 +08:00
|
|
|
if (aac->in_reset)
|
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2005-05-17 09:28:42 +08:00
|
|
|
* Allocate and initialize a Fib
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2006-08-03 23:03:07 +08:00
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(aac)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_init(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
synchronizecmd = fib_data(cmd_fibcontext);
|
|
|
|
synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
|
2007-03-16 01:26:55 +08:00
|
|
|
synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
|
2007-07-27 21:48:49 +08:00
|
|
|
synchronizecmd->count =
|
2005-04-17 06:20:36 +08:00
|
|
|
cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
2006-02-02 01:30:55 +08:00
|
|
|
status = aac_fib_send(ContainerCommand,
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd_fibcontext,
|
|
|
|
sizeof(struct aac_synchronize),
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback)synchronize_callback,
|
|
|
|
(void *)scsicmd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2006-03-28 01:43:40 +08:00
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
2006-03-28 01:43:40 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-07-27 21:48:49 +08:00
|
|
|
printk(KERN_WARNING
|
2006-02-02 01:30:55 +08:00
|
|
|
"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
|
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
}
|
|
|
|
|
2008-05-01 04:03:42 +08:00
|
|
|
static void aac_start_stop_callback(void *context, struct fib *fibptr)
|
|
|
|
{
|
|
|
|
struct scsi_cmnd *scsicmd = context;
|
|
|
|
|
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
|
|
|
BUG_ON(fibptr == NULL);
|
|
|
|
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
|
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_start_stop(struct scsi_cmnd *scsicmd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct fib *cmd_fibcontext;
|
|
|
|
struct aac_power_management *pmcmd;
|
|
|
|
struct scsi_device *sdev = scsicmd->device;
|
|
|
|
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
|
|
|
|
|
|
|
|
if (!(aac->supplement_adapter_info.SupportedOptions2 &
|
|
|
|
AAC_OPTION_POWER_MANAGEMENT)) {
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aac->in_reset)
|
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate and initialize a Fib
|
|
|
|
*/
|
|
|
|
cmd_fibcontext = aac_fib_alloc(aac);
|
|
|
|
if (!cmd_fibcontext)
|
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
|
|
|
|
aac_fib_init(cmd_fibcontext);
|
|
|
|
|
|
|
|
pmcmd = fib_data(cmd_fibcontext);
|
|
|
|
pmcmd->command = cpu_to_le32(VM_ContainerConfig);
|
|
|
|
pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
|
|
|
|
/* Eject bit ignored, not relevant */
|
|
|
|
pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
|
|
|
|
cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
|
|
|
|
pmcmd->cid = cpu_to_le32(sdev_id(sdev));
|
|
|
|
pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
|
|
|
|
cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now send the Fib to the adapter
|
|
|
|
*/
|
|
|
|
status = aac_fib_send(ContainerCommand,
|
|
|
|
cmd_fibcontext,
|
|
|
|
sizeof(struct aac_power_management),
|
|
|
|
FsaNormal,
|
|
|
|
0, 1,
|
|
|
|
(fib_callback)aac_start_stop_callback,
|
|
|
|
(void *)scsicmd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
|
|
|
return SCSI_MLQUEUE_HOST_BUSY;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* aac_scsi_cmd() - Process SCSI command
|
|
|
|
* @scsicmd: SCSI command block
|
|
|
|
*
|
|
|
|
* Emulate a SCSI command and queue the required request for the
|
|
|
|
* aacraid firmware.
|
|
|
|
*/
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
|
|
|
|
{
|
2007-06-12 04:17:55 +08:00
|
|
|
u32 cid;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct Scsi_Host *host = scsicmd->device->host;
|
|
|
|
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2006-08-03 23:03:07 +08:00
|
|
|
if (fsa_dev_ptr == NULL)
|
|
|
|
return -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* If the bus, id or lun is out of range, return fail
|
|
|
|
* Test does not apply to ID 16, the pseudo id for the controller
|
|
|
|
* itself.
|
|
|
|
*/
|
2007-06-12 04:17:55 +08:00
|
|
|
cid = scmd_id(scsicmd);
|
|
|
|
if (cid != host->this_id) {
|
|
|
|
if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
|
|
|
|
if((cid >= dev->maximum_num_containers) ||
|
2006-03-28 01:43:25 +08:00
|
|
|
(scsicmd->device->lun != 0)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_NO_CONNECT << 16;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the target container doesn't exist, it may have
|
|
|
|
* been newly created
|
|
|
|
*/
|
2008-05-01 04:03:42 +08:00
|
|
|
if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
|
|
|
|
(fsa_dev_ptr[cid].sense_data.sense_key ==
|
|
|
|
NOT_READY)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (scsicmd->cmnd[0]) {
|
2014-11-17 21:25:19 +08:00
|
|
|
case SERVICE_ACTION_IN_16:
|
2005-09-23 00:15:24 +08:00
|
|
|
if (!(dev->raw_io_interface) ||
|
|
|
|
!(dev->raw_io_64) ||
|
|
|
|
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
case INQUIRY:
|
|
|
|
case READ_CAPACITY:
|
|
|
|
case TEST_UNIT_READY:
|
2006-08-03 23:03:30 +08:00
|
|
|
if (dev->in_reset)
|
|
|
|
return -1;
|
2007-03-16 03:55:07 +08:00
|
|
|
return _aac_probe_container(scsicmd,
|
|
|
|
aac_probe_container_callback2);
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { /* check for physical non-dasd devices */
|
2008-01-18 01:25:07 +08:00
|
|
|
if (dev->nondasd_support || expose_physicals ||
|
|
|
|
dev->jbod) {
|
2006-08-03 23:03:30 +08:00
|
|
|
if (dev->in_reset)
|
|
|
|
return -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
return aac_send_srb_fib(scsicmd);
|
|
|
|
} else {
|
|
|
|
scsicmd->result = DID_NO_CONNECT << 16;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* else Command for the controller itself
|
|
|
|
*/
|
|
|
|
else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */
|
2008-01-16 23:39:06 +08:00
|
|
|
(scsicmd->cmnd[0] != TEST_UNIT_READY))
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
|
|
|
|
ASENCODE_INVALID_COMMAND, 0, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
2008-01-14 23:25:33 +08:00
|
|
|
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle commands here that don't really require going out to the adapter */
|
|
|
|
switch (scsicmd->cmnd[0]) {
|
|
|
|
case INQUIRY:
|
|
|
|
{
|
2005-08-16 01:50:24 +08:00
|
|
|
struct inquiry_data inq_data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-06-12 04:17:55 +08:00
|
|
|
dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
|
2005-08-16 01:50:24 +08:00
|
|
|
memset(&inq_data, 0, sizeof (struct inquiry_data));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-04-01 22:16:08 +08:00
|
|
|
if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) {
|
2007-07-18 02:01:28 +08:00
|
|
|
char *arr = (char *)&inq_data;
|
|
|
|
|
|
|
|
/* EVPD bit set */
|
|
|
|
arr[0] = (scmd_id(scsicmd) == host->this_id) ?
|
|
|
|
INQD_PDT_PROC : INQD_PDT_DA;
|
|
|
|
if (scsicmd->cmnd[2] == 0) {
|
|
|
|
/* supported vital product data pages */
|
2015-03-26 22:41:26 +08:00
|
|
|
arr[3] = 3;
|
2007-07-18 02:01:28 +08:00
|
|
|
arr[4] = 0x0;
|
|
|
|
arr[5] = 0x80;
|
2015-03-26 22:41:26 +08:00
|
|
|
arr[6] = 0x83;
|
2007-07-18 02:01:28 +08:00
|
|
|
arr[1] = scsicmd->cmnd[2];
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq_data,
|
|
|
|
sizeof(inq_data));
|
2007-07-18 02:01:28 +08:00
|
|
|
scsicmd->result = DID_OK << 16 |
|
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
} else if (scsicmd->cmnd[2] == 0x80) {
|
|
|
|
/* unit serial number page */
|
|
|
|
arr[3] = setinqserial(dev, &arr[4],
|
|
|
|
scmd_id(scsicmd));
|
|
|
|
arr[1] = scsicmd->cmnd[2];
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq_data,
|
|
|
|
sizeof(inq_data));
|
2009-04-01 22:16:08 +08:00
|
|
|
if (aac_wwn != 2)
|
|
|
|
return aac_get_container_serial(
|
|
|
|
scsicmd);
|
2015-03-26 22:41:26 +08:00
|
|
|
scsicmd->result = DID_OK << 16 |
|
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
} else if (scsicmd->cmnd[2] == 0x83) {
|
|
|
|
/* vpd page 0x83 - Device Identification Page */
|
|
|
|
char *sno = (char *)&inq_data;
|
|
|
|
sno[3] = setinqserial(dev, &sno[4],
|
|
|
|
scmd_id(scsicmd));
|
|
|
|
if (aac_wwn != 2)
|
|
|
|
return aac_get_container_serial(
|
|
|
|
scsicmd);
|
2009-04-01 22:16:08 +08:00
|
|
|
scsicmd->result = DID_OK << 16 |
|
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
2007-07-18 02:01:28 +08:00
|
|
|
} else {
|
|
|
|
/* vpd page not implemented */
|
|
|
|
scsicmd->result = DID_OK << 16 |
|
|
|
|
COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD,
|
|
|
|
ASENCODE_NO_SENSE, 7, 2);
|
2007-07-18 02:01:28 +08:00
|
|
|
memcpy(scsicmd->sense_buffer,
|
|
|
|
&dev->fsa_dev[cid].sense_data,
|
2008-01-14 23:25:33 +08:00
|
|
|
min_t(size_t,
|
|
|
|
sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2007-07-18 02:01:28 +08:00
|
|
|
}
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-16 01:50:24 +08:00
|
|
|
inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
|
|
|
|
inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
|
|
|
|
inq_data.inqd_len = 31;
|
2005-04-17 06:20:36 +08:00
|
|
|
/*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */
|
2005-08-16 01:50:24 +08:00
|
|
|
inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Set the Vendor, Product, and Revision Level
|
|
|
|
* see: <vendor>.c i.e. aac.c
|
|
|
|
*/
|
2007-06-12 04:17:55 +08:00
|
|
|
if (cid == host->this_id) {
|
2006-06-09 13:23:48 +08:00
|
|
|
setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
|
2005-08-16 01:50:24 +08:00
|
|
|
inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq_data,
|
|
|
|
sizeof(inq_data));
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-08-03 23:03:30 +08:00
|
|
|
if (dev->in_reset)
|
|
|
|
return -1;
|
2005-10-25 01:51:53 +08:00
|
|
|
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
|
2005-08-16 01:50:24 +08:00
|
|
|
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
2007-03-16 01:26:55 +08:00
|
|
|
return aac_get_container_name(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2014-11-17 21:25:19 +08:00
|
|
|
case SERVICE_ACTION_IN_16:
|
2005-09-23 00:15:24 +08:00
|
|
|
if (!(dev->raw_io_interface) ||
|
|
|
|
!(dev->raw_io_64) ||
|
|
|
|
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
|
|
|
|
break;
|
|
|
|
{
|
|
|
|
u64 capacity;
|
2005-11-09 06:26:33 +08:00
|
|
|
char cp[13];
|
2008-02-25 07:25:23 +08:00
|
|
|
unsigned int alloc_len;
|
2005-09-23 00:15:24 +08:00
|
|
|
|
|
|
|
dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
|
|
|
|
capacity = fsa_dev_ptr[cid].size - 1;
|
|
|
|
cp[0] = (capacity >> 56) & 0xff;
|
|
|
|
cp[1] = (capacity >> 48) & 0xff;
|
|
|
|
cp[2] = (capacity >> 40) & 0xff;
|
|
|
|
cp[3] = (capacity >> 32) & 0xff;
|
|
|
|
cp[4] = (capacity >> 24) & 0xff;
|
|
|
|
cp[5] = (capacity >> 16) & 0xff;
|
|
|
|
cp[6] = (capacity >> 8) & 0xff;
|
|
|
|
cp[7] = (capacity >> 0) & 0xff;
|
2015-03-26 22:41:24 +08:00
|
|
|
cp[8] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
|
|
|
|
cp[9] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
|
|
|
|
cp[10] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
|
|
|
|
cp[11] = (fsa_dev_ptr[cid].block_size) & 0xff;
|
2005-11-09 06:26:33 +08:00
|
|
|
cp[12] = 0;
|
|
|
|
|
2008-02-25 07:25:23 +08:00
|
|
|
alloc_len = ((scsicmd->cmnd[10] << 24)
|
|
|
|
+ (scsicmd->cmnd[11] << 16)
|
|
|
|
+ (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]);
|
|
|
|
|
|
|
|
alloc_len = min_t(size_t, alloc_len, sizeof(cp));
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len);
|
2008-02-25 07:25:23 +08:00
|
|
|
if (alloc_len < scsi_bufflen(scsicmd))
|
|
|
|
scsi_set_resid(scsicmd,
|
|
|
|
scsi_bufflen(scsicmd) - alloc_len);
|
2005-09-23 00:15:24 +08:00
|
|
|
|
|
|
|
/* Do not cache partition table for arrays */
|
|
|
|
scsicmd->device->removable = 1;
|
|
|
|
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case READ_CAPACITY:
|
|
|
|
{
|
|
|
|
u32 capacity;
|
2005-08-16 01:50:24 +08:00
|
|
|
char cp[8];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
|
2005-09-23 00:15:24 +08:00
|
|
|
if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
capacity = fsa_dev_ptr[cid].size - 1;
|
|
|
|
else
|
|
|
|
capacity = (u32)-1;
|
2005-08-16 01:50:24 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
cp[0] = (capacity >> 24) & 0xff;
|
|
|
|
cp[1] = (capacity >> 16) & 0xff;
|
|
|
|
cp[2] = (capacity >> 8) & 0xff;
|
|
|
|
cp[3] = (capacity >> 0) & 0xff;
|
2015-03-26 22:41:24 +08:00
|
|
|
cp[4] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff;
|
|
|
|
cp[5] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff;
|
|
|
|
cp[6] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff;
|
|
|
|
cp[7] = (fsa_dev_ptr[cid].block_size) & 0xff;
|
2008-03-09 12:44:34 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
|
2005-09-23 00:15:24 +08:00
|
|
|
/* Do not cache partition table for arrays */
|
|
|
|
scsicmd->device->removable = 1;
|
2008-05-01 04:03:42 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_GOOD;
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MODE_SENSE:
|
|
|
|
{
|
2007-05-19 02:51:34 +08:00
|
|
|
int mode_buf_length = 4;
|
2015-03-26 22:41:24 +08:00
|
|
|
u32 capacity;
|
|
|
|
aac_modep_data mpd;
|
|
|
|
|
|
|
|
if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
|
|
|
|
capacity = fsa_dev_ptr[cid].size - 1;
|
|
|
|
else
|
|
|
|
capacity = (u32)-1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dprintk((KERN_DEBUG "MODE SENSE command.\n"));
|
2015-03-26 22:41:24 +08:00
|
|
|
memset((char *)&mpd, 0, sizeof(aac_modep_data));
|
|
|
|
|
|
|
|
/* Mode data length */
|
|
|
|
mpd.hd.data_length = sizeof(mpd.hd) - 1;
|
|
|
|
/* Medium type - default */
|
|
|
|
mpd.hd.med_type = 0;
|
|
|
|
/* Device-specific param,
|
|
|
|
bit 8: 0/1 = write enabled/protected
|
|
|
|
bit 4: 0/1 = FUA enabled */
|
|
|
|
mpd.hd.dev_par = 0;
|
|
|
|
|
2008-01-09 04:01:07 +08:00
|
|
|
if (dev->raw_io_interface && ((aac_cache & 5) != 1))
|
2015-03-26 22:41:24 +08:00
|
|
|
mpd.hd.dev_par = 0x10;
|
|
|
|
if (scsicmd->cmnd[1] & 0x8)
|
|
|
|
mpd.hd.bd_length = 0; /* Block descriptor length */
|
|
|
|
else {
|
|
|
|
mpd.hd.bd_length = sizeof(mpd.bd);
|
|
|
|
mpd.hd.data_length += mpd.hd.bd_length;
|
|
|
|
mpd.bd.block_length[0] =
|
|
|
|
(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
|
|
|
|
mpd.bd.block_length[1] =
|
|
|
|
(fsa_dev_ptr[cid].block_size >> 8) & 0xff;
|
|
|
|
mpd.bd.block_length[2] =
|
|
|
|
fsa_dev_ptr[cid].block_size & 0xff;
|
2015-03-26 22:41:26 +08:00
|
|
|
|
|
|
|
mpd.mpc_buf[0] = scsicmd->cmnd[2];
|
|
|
|
if (scsicmd->cmnd[2] == 0x1C) {
|
|
|
|
/* page length */
|
|
|
|
mpd.mpc_buf[1] = 0xa;
|
|
|
|
/* Mode data length */
|
|
|
|
mpd.hd.data_length = 23;
|
|
|
|
} else {
|
|
|
|
/* Mode data length */
|
|
|
|
mpd.hd.data_length = 15;
|
|
|
|
}
|
|
|
|
|
2015-03-26 22:41:24 +08:00
|
|
|
if (capacity > 0xffffff) {
|
|
|
|
mpd.bd.block_count[0] = 0xff;
|
|
|
|
mpd.bd.block_count[1] = 0xff;
|
|
|
|
mpd.bd.block_count[2] = 0xff;
|
|
|
|
} else {
|
|
|
|
mpd.bd.block_count[0] = (capacity >> 16) & 0xff;
|
|
|
|
mpd.bd.block_count[1] = (capacity >> 8) & 0xff;
|
|
|
|
mpd.bd.block_count[2] = capacity & 0xff;
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 02:51:34 +08:00
|
|
|
if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
|
|
|
|
((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
|
2015-03-26 22:41:24 +08:00
|
|
|
mpd.hd.data_length += 3;
|
|
|
|
mpd.mpc_buf[0] = 8;
|
|
|
|
mpd.mpc_buf[1] = 1;
|
|
|
|
mpd.mpc_buf[2] = ((aac_cache & 6) == 2)
|
2008-01-09 04:01:07 +08:00
|
|
|
? 0 : 0x04; /* WCE */
|
2015-03-26 22:41:24 +08:00
|
|
|
mode_buf_length = sizeof(mpd);
|
2007-05-19 02:51:34 +08:00
|
|
|
}
|
2015-03-26 22:41:26 +08:00
|
|
|
|
|
|
|
if (mode_buf_length > scsicmd->cmnd[4])
|
|
|
|
mode_buf_length = scsicmd->cmnd[4];
|
|
|
|
else
|
|
|
|
mode_buf_length = sizeof(mpd);
|
2015-03-26 22:41:24 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd,
|
|
|
|
(char *)&mpd,
|
|
|
|
mode_buf_length);
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
case MODE_SENSE_10:
|
|
|
|
{
|
2015-03-26 22:41:24 +08:00
|
|
|
u32 capacity;
|
2007-05-19 02:51:34 +08:00
|
|
|
int mode_buf_length = 8;
|
2015-03-26 22:41:24 +08:00
|
|
|
aac_modep10_data mpd10;
|
|
|
|
|
|
|
|
if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
|
|
|
|
capacity = fsa_dev_ptr[cid].size - 1;
|
|
|
|
else
|
|
|
|
capacity = (u32)-1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
|
2015-03-26 22:41:24 +08:00
|
|
|
memset((char *)&mpd10, 0, sizeof(aac_modep10_data));
|
|
|
|
/* Mode data length (MSB) */
|
|
|
|
mpd10.hd.data_length[0] = 0;
|
|
|
|
/* Mode data length (LSB) */
|
|
|
|
mpd10.hd.data_length[1] = sizeof(mpd10.hd) - 1;
|
|
|
|
/* Medium type - default */
|
|
|
|
mpd10.hd.med_type = 0;
|
|
|
|
/* Device-specific param,
|
|
|
|
bit 8: 0/1 = write enabled/protected
|
|
|
|
bit 4: 0/1 = FUA enabled */
|
|
|
|
mpd10.hd.dev_par = 0;
|
|
|
|
|
2008-01-09 04:01:07 +08:00
|
|
|
if (dev->raw_io_interface && ((aac_cache & 5) != 1))
|
2015-03-26 22:41:24 +08:00
|
|
|
mpd10.hd.dev_par = 0x10;
|
|
|
|
mpd10.hd.rsrvd[0] = 0; /* reserved */
|
|
|
|
mpd10.hd.rsrvd[1] = 0; /* reserved */
|
|
|
|
if (scsicmd->cmnd[1] & 0x8) {
|
|
|
|
/* Block descriptor length (MSB) */
|
|
|
|
mpd10.hd.bd_length[0] = 0;
|
|
|
|
/* Block descriptor length (LSB) */
|
|
|
|
mpd10.hd.bd_length[1] = 0;
|
|
|
|
} else {
|
|
|
|
mpd10.hd.bd_length[0] = 0;
|
|
|
|
mpd10.hd.bd_length[1] = sizeof(mpd10.bd);
|
|
|
|
|
|
|
|
mpd10.hd.data_length[1] += mpd10.hd.bd_length[1];
|
|
|
|
|
|
|
|
mpd10.bd.block_length[0] =
|
|
|
|
(fsa_dev_ptr[cid].block_size >> 16) & 0xff;
|
|
|
|
mpd10.bd.block_length[1] =
|
|
|
|
(fsa_dev_ptr[cid].block_size >> 8) & 0xff;
|
|
|
|
mpd10.bd.block_length[2] =
|
|
|
|
fsa_dev_ptr[cid].block_size & 0xff;
|
|
|
|
|
|
|
|
if (capacity > 0xffffff) {
|
|
|
|
mpd10.bd.block_count[0] = 0xff;
|
|
|
|
mpd10.bd.block_count[1] = 0xff;
|
|
|
|
mpd10.bd.block_count[2] = 0xff;
|
|
|
|
} else {
|
|
|
|
mpd10.bd.block_count[0] =
|
|
|
|
(capacity >> 16) & 0xff;
|
|
|
|
mpd10.bd.block_count[1] =
|
|
|
|
(capacity >> 8) & 0xff;
|
|
|
|
mpd10.bd.block_count[2] =
|
|
|
|
capacity & 0xff;
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 02:51:34 +08:00
|
|
|
if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
|
|
|
|
((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
|
2015-03-26 22:41:24 +08:00
|
|
|
mpd10.hd.data_length[1] += 3;
|
|
|
|
mpd10.mpc_buf[0] = 8;
|
|
|
|
mpd10.mpc_buf[1] = 1;
|
|
|
|
mpd10.mpc_buf[2] = ((aac_cache & 6) == 2)
|
2008-01-09 04:01:07 +08:00
|
|
|
? 0 : 0x04; /* WCE */
|
2015-03-26 22:41:24 +08:00
|
|
|
mode_buf_length = sizeof(mpd10);
|
2007-05-19 02:51:34 +08:00
|
|
|
if (mode_buf_length > scsicmd->cmnd[8])
|
|
|
|
mode_buf_length = scsicmd->cmnd[8];
|
|
|
|
}
|
2015-03-26 22:41:24 +08:00
|
|
|
scsi_sg_copy_from_buffer(scsicmd,
|
|
|
|
(char *)&mpd10,
|
|
|
|
mode_buf_length);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
case REQUEST_SENSE:
|
|
|
|
dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
|
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
|
|
|
|
memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case ALLOW_MEDIUM_REMOVAL:
|
|
|
|
dprintk((KERN_DEBUG "LOCK command.\n"));
|
|
|
|
if (scsicmd->cmnd[4])
|
|
|
|
fsa_dev_ptr[cid].locked = 1;
|
|
|
|
else
|
|
|
|
fsa_dev_ptr[cid].locked = 0;
|
|
|
|
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* These commands are all No-Ops
|
|
|
|
*/
|
|
|
|
case TEST_UNIT_READY:
|
2008-05-01 04:03:42 +08:00
|
|
|
if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
|
|
|
|
SAM_STAT_CHECK_CONDITION;
|
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
NOT_READY, SENCODE_BECOMING_READY,
|
|
|
|
ASENCODE_BECOMING_READY, 0, 0);
|
|
|
|
memcpy(scsicmd->sense_buffer,
|
|
|
|
&dev->fsa_dev[cid].sense_data,
|
|
|
|
min_t(size_t,
|
|
|
|
sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* FALLTHRU */
|
2005-04-17 06:20:36 +08:00
|
|
|
case RESERVE:
|
|
|
|
case RELEASE:
|
|
|
|
case REZERO_UNIT:
|
|
|
|
case REASSIGN_BLOCKS:
|
|
|
|
case SEEK_10:
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
2008-05-01 04:03:42 +08:00
|
|
|
|
|
|
|
case START_STOP:
|
|
|
|
return aac_start_stop(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-01-16 23:39:06 +08:00
|
|
|
switch (scsicmd->cmnd[0])
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
case READ_6:
|
|
|
|
case READ_10:
|
2005-09-23 00:15:24 +08:00
|
|
|
case READ_12:
|
|
|
|
case READ_16:
|
2006-08-03 23:03:30 +08:00
|
|
|
if (dev->in_reset)
|
|
|
|
return -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Hack to keep track of ordinal number of the device that
|
|
|
|
* corresponds to a container. Needed to convert
|
|
|
|
* containers to /dev/sd device names
|
|
|
|
*/
|
2008-01-16 23:39:06 +08:00
|
|
|
|
2005-09-23 00:15:24 +08:00
|
|
|
if (scsicmd->request->rq_disk)
|
|
|
|
strlcpy(fsa_dev_ptr[cid].devname,
|
|
|
|
scsicmd->request->rq_disk->disk_name,
|
2008-01-16 23:39:06 +08:00
|
|
|
min(sizeof(fsa_dev_ptr[cid].devname),
|
2005-09-23 00:15:24 +08:00
|
|
|
sizeof(scsicmd->request->rq_disk->disk_name) + 1));
|
2006-03-28 01:43:40 +08:00
|
|
|
|
2007-03-16 01:26:55 +08:00
|
|
|
return aac_read(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
case WRITE_6:
|
|
|
|
case WRITE_10:
|
2005-09-23 00:15:24 +08:00
|
|
|
case WRITE_12:
|
|
|
|
case WRITE_16:
|
2006-08-03 23:03:30 +08:00
|
|
|
if (dev->in_reset)
|
|
|
|
return -1;
|
2007-03-16 01:26:55 +08:00
|
|
|
return aac_write(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
case SYNCHRONIZE_CACHE:
|
2008-01-09 04:01:07 +08:00
|
|
|
if (((aac_cache & 6) == 6) && dev->cache_protected) {
|
|
|
|
scsicmd->result = DID_OK << 16 |
|
|
|
|
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Issue FIB to tell Firmware to flush it's cache */
|
2008-01-09 04:01:07 +08:00
|
|
|
if ((aac_cache & 6) != 2)
|
|
|
|
return aac_synchronize(scsicmd);
|
|
|
|
/* FALLTHRU */
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* Unhandled commands
|
|
|
|
*/
|
2005-05-17 09:28:42 +08:00
|
|
|
dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
|
[SCSI] aacraid: do not set valid bit in sense information
Luben Tuikov [mailto:ltuikov@yahoo.com] sez:
> Just as in your case and Tony's case, which I presume
> uses the same RAID firmware vendor, it would've
> probably been better if the RAID firmware vendor
> fixed the firmware to not set the VALID bit if the
> INFORMATION field is not valid.
Point taken regarding the aacraid driver. Dropped the VALID bit, and
then did some cleanup/simplification of the set_sense procedure and
the associated parameters. Mike did some preliminary tests when the
VALID bit was dropped before the 'Re: [PATCH] [SCSI] sd: make error
handling more robust' patches came on the scene. The change in the
SCSI subsystem does make this enclosed aacraid patch unnecessary, so
this aacraid patch is merely post battle ground cleanup. If the
simplification is an issue, repugnant, too much for a back-port to the
stable trees or clouds the point, this patch could be happily
distilled down to:
diff -ru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c 2008-02-06 16:26:45.834938955 -0500
+++ b/drivers/scsi/aacraid/aachba.c 2008-02-06 16:32:01.109035329 -0500
@@ -865,7 +865,7 @@
u32 residue)
{
- sense_buf[0] = 0xF0; /* Sense data valid, err code 70h (current error) */
+ sense_buf[0] = 0x70; /* Sense data invalid, err code 70h (current error) */
sense_buf[1] = 0; /* Segment number, always zero */
if (incorrect_length) {
Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2008-02-07 05:54:12 +08:00
|
|
|
set_sense(&dev->fsa_dev[cid].sense_data,
|
|
|
|
ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
|
|
|
|
ASENCODE_INVALID_COMMAND, 0, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
|
2008-01-14 23:25:33 +08:00
|
|
|
min_t(size_t,
|
|
|
|
sizeof(dev->fsa_dev[cid].sense_data),
|
|
|
|
SCSI_SENSE_BUFFERSIZE));
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int query_disk(struct aac_dev *dev, void __user *arg)
|
|
|
|
{
|
|
|
|
struct aac_query_disk qd;
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr;
|
|
|
|
|
|
|
|
fsa_dev_ptr = dev->fsa_dev;
|
2006-08-03 23:03:07 +08:00
|
|
|
if (!fsa_dev_ptr)
|
2006-09-19 23:59:23 +08:00
|
|
|
return -EBUSY;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
|
|
|
|
return -EFAULT;
|
|
|
|
if (qd.cnum == -1)
|
2006-03-28 01:43:25 +08:00
|
|
|
qd.cnum = qd.id;
|
2008-01-16 23:39:06 +08:00
|
|
|
else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
|
|
|
|
return -EINVAL;
|
|
|
|
qd.instance = dev->scsi_host_ptr->host_no;
|
|
|
|
qd.bus = 0;
|
|
|
|
qd.id = CONTAINER_TO_ID(qd.cnum);
|
|
|
|
qd.lun = CONTAINER_TO_LUN(qd.cnum);
|
|
|
|
}
|
|
|
|
else return -EINVAL;
|
|
|
|
|
2007-07-17 22:59:19 +08:00
|
|
|
qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
qd.locked = fsa_dev_ptr[qd.cnum].locked;
|
|
|
|
qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
|
|
|
|
|
|
|
|
if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
|
|
|
|
qd.unmapped = 1;
|
|
|
|
else
|
|
|
|
qd.unmapped = 0;
|
|
|
|
|
|
|
|
strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
|
|
|
|
min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
|
|
|
|
|
|
|
|
if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
|
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int force_delete_disk(struct aac_dev *dev, void __user *arg)
|
|
|
|
{
|
|
|
|
struct aac_delete_disk dd;
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr;
|
|
|
|
|
|
|
|
fsa_dev_ptr = dev->fsa_dev;
|
2006-09-19 23:59:23 +08:00
|
|
|
if (!fsa_dev_ptr)
|
|
|
|
return -EBUSY;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (dd.cnum >= dev->maximum_num_containers)
|
|
|
|
return -EINVAL;
|
|
|
|
/*
|
|
|
|
* Mark this container as being deleted.
|
|
|
|
*/
|
|
|
|
fsa_dev_ptr[dd.cnum].deleted = 1;
|
|
|
|
/*
|
|
|
|
* Mark the container as no longer valid
|
|
|
|
*/
|
|
|
|
fsa_dev_ptr[dd.cnum].valid = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int delete_disk(struct aac_dev *dev, void __user *arg)
|
|
|
|
{
|
|
|
|
struct aac_delete_disk dd;
|
|
|
|
struct fsa_dev_info *fsa_dev_ptr;
|
|
|
|
|
|
|
|
fsa_dev_ptr = dev->fsa_dev;
|
2006-08-03 23:03:07 +08:00
|
|
|
if (!fsa_dev_ptr)
|
2006-09-19 23:59:23 +08:00
|
|
|
return -EBUSY;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (dd.cnum >= dev->maximum_num_containers)
|
|
|
|
return -EINVAL;
|
|
|
|
/*
|
|
|
|
* If the container is locked, it can not be deleted by the API.
|
|
|
|
*/
|
|
|
|
if (fsa_dev_ptr[dd.cnum].locked)
|
|
|
|
return -EBUSY;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Mark the container as no longer being valid.
|
|
|
|
*/
|
|
|
|
fsa_dev_ptr[dd.cnum].valid = 0;
|
|
|
|
fsa_dev_ptr[dd.cnum].devname[0] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case FSACTL_QUERY_DISK:
|
|
|
|
return query_disk(dev, arg);
|
|
|
|
case FSACTL_DELETE_DISK:
|
|
|
|
return delete_disk(dev, arg);
|
|
|
|
case FSACTL_FORCE_DELETE_DISK:
|
|
|
|
return force_delete_disk(dev, arg);
|
|
|
|
case FSACTL_GET_CONTAINERS:
|
|
|
|
return aac_get_containers(dev);
|
|
|
|
default:
|
|
|
|
return -ENOTTY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* aac_srb_callback
|
|
|
|
* @context: the context set in the fib - here it is scsi cmd
|
|
|
|
* @fibptr: pointer to the fib
|
|
|
|
*
|
|
|
|
* Handles the completion of a scsi command to a non dasd device
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void aac_srb_callback(void *context, struct fib * fibptr)
|
|
|
|
{
|
|
|
|
struct aac_dev *dev;
|
|
|
|
struct aac_srb_reply *srbreply;
|
|
|
|
struct scsi_cmnd *scsicmd;
|
|
|
|
|
|
|
|
scsicmd = (struct scsi_cmnd *) context;
|
2007-03-16 01:27:45 +08:00
|
|
|
|
|
|
|
if (!aac_valid_context(scsicmd, fibptr))
|
|
|
|
return;
|
|
|
|
|
2006-06-23 17:06:06 +08:00
|
|
|
BUG_ON(fibptr == NULL);
|
2007-06-12 04:17:55 +08:00
|
|
|
dev = fibptr->dev;
|
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
scsi_dma_unmap(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
/* expose physical device if expose_physicald flag is on */
|
|
|
|
if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
|
|
|
|
&& expose_physicals > 0)
|
|
|
|
aac_expose_phy_device(scsicmd);
|
|
|
|
|
|
|
|
srbreply = (struct aac_srb_reply *) fib_data(fibptr);
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
|
2007-05-26 01:00:42 +08:00
|
|
|
|
2012-07-14 20:48:51 +08:00
|
|
|
if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
|
|
|
|
/* fast response */
|
|
|
|
srbreply->srb_status = cpu_to_le32(SRB_STATUS_SUCCESS);
|
|
|
|
srbreply->scsi_status = cpu_to_le32(SAM_STAT_GOOD);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Calculate resid for sg
|
|
|
|
*/
|
|
|
|
scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
|
|
|
|
- le32_to_cpu(srbreply->data_xfer_length));
|
2015-08-28 18:38:37 +08:00
|
|
|
/*
|
|
|
|
* First check the fib status
|
|
|
|
*/
|
2010-05-10 19:12:28 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
if (le32_to_cpu(srbreply->status) != ST_OK) {
|
|
|
|
int len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
|
|
|
|
len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
|
|
|
|
SCSI_SENSE_BUFFERSIZE);
|
|
|
|
scsicmd->result = DID_ERROR << 16
|
|
|
|
| COMMAND_COMPLETE << 8
|
|
|
|
| SAM_STAT_CHECK_CONDITION;
|
|
|
|
memcpy(scsicmd->sense_buffer,
|
|
|
|
srbreply->sense_data, len);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
/*
|
|
|
|
* Next check the srb status
|
|
|
|
*/
|
|
|
|
switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
|
|
|
|
case SRB_STATUS_ERROR_RECOVERY:
|
|
|
|
case SRB_STATUS_PENDING:
|
|
|
|
case SRB_STATUS_SUCCESS:
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
|
|
|
case SRB_STATUS_DATA_OVERRUN:
|
|
|
|
switch (scsicmd->cmnd[0]) {
|
|
|
|
case READ_6:
|
|
|
|
case WRITE_6:
|
|
|
|
case READ_10:
|
|
|
|
case WRITE_10:
|
|
|
|
case READ_12:
|
|
|
|
case WRITE_12:
|
|
|
|
case READ_16:
|
|
|
|
case WRITE_16:
|
|
|
|
if (le32_to_cpu(srbreply->data_xfer_length)
|
|
|
|
< scsicmd->underflow)
|
|
|
|
printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
|
|
|
|
else
|
|
|
|
printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
|
|
|
|
scsicmd->result = DID_ERROR << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
|
|
|
case INQUIRY: {
|
|
|
|
scsicmd->result = DID_OK << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
break;
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_ABORTED:
|
|
|
|
scsicmd->result = DID_ABORT << 16 | ABORT << 8;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_ABORT_FAILED:
|
|
|
|
/*
|
|
|
|
* Not sure about this one - but assuming the
|
|
|
|
* hba was trying to abort for some reason
|
|
|
|
*/
|
|
|
|
scsicmd->result = DID_ERROR << 16 | ABORT << 8;
|
|
|
|
break;
|
|
|
|
case SRB_STATUS_PARITY_ERROR:
|
|
|
|
scsicmd->result = DID_PARITY << 16
|
|
|
|
| MSG_PARITY_ERROR << 8;
|
|
|
|
break;
|
|
|
|
case SRB_STATUS_NO_DEVICE:
|
|
|
|
case SRB_STATUS_INVALID_PATH_ID:
|
|
|
|
case SRB_STATUS_INVALID_TARGET_ID:
|
|
|
|
case SRB_STATUS_INVALID_LUN:
|
|
|
|
case SRB_STATUS_SELECTION_TIMEOUT:
|
|
|
|
scsicmd->result = DID_NO_CONNECT << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_COMMAND_TIMEOUT:
|
|
|
|
case SRB_STATUS_TIMEOUT:
|
|
|
|
scsicmd->result = DID_TIME_OUT << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_BUSY:
|
|
|
|
scsicmd->result = DID_BUS_BUSY << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_BUS_RESET:
|
|
|
|
scsicmd->result = DID_RESET << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-08-28 18:38:37 +08:00
|
|
|
case SRB_STATUS_MESSAGE_REJECTED:
|
|
|
|
scsicmd->result = DID_ERROR << 16
|
|
|
|
| MESSAGE_REJECT << 8;
|
|
|
|
break;
|
|
|
|
case SRB_STATUS_REQUEST_FLUSHED:
|
|
|
|
case SRB_STATUS_ERROR:
|
|
|
|
case SRB_STATUS_INVALID_REQUEST:
|
|
|
|
case SRB_STATUS_REQUEST_SENSE_FAILED:
|
|
|
|
case SRB_STATUS_NO_HBA:
|
|
|
|
case SRB_STATUS_UNEXPECTED_BUS_FREE:
|
|
|
|
case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
|
|
|
|
case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
|
|
|
|
case SRB_STATUS_DELAYED_RETRY:
|
|
|
|
case SRB_STATUS_BAD_FUNCTION:
|
|
|
|
case SRB_STATUS_NOT_STARTED:
|
|
|
|
case SRB_STATUS_NOT_IN_USE:
|
|
|
|
case SRB_STATUS_FORCE_ABORT:
|
|
|
|
case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
|
|
|
|
default:
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef AAC_DETAILED_STATUS_INFO
|
2015-08-28 18:38:37 +08:00
|
|
|
printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
|
|
|
|
le32_to_cpu(srbreply->srb_status) & 0x3F,
|
|
|
|
aac_get_status_string(
|
|
|
|
le32_to_cpu(srbreply->srb_status) & 0x3F),
|
|
|
|
scsicmd->cmnd[0],
|
|
|
|
le32_to_cpu(srbreply->scsi_status));
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|
2015-08-28 18:38:37 +08:00
|
|
|
if ((scsicmd->cmnd[0] == ATA_12)
|
|
|
|
|| (scsicmd->cmnd[0] == ATA_16)) {
|
|
|
|
if (scsicmd->cmnd[2] & (0x01 << 5)) {
|
|
|
|
scsicmd->result = DID_OK << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
2010-05-10 19:17:57 +08:00
|
|
|
break;
|
2015-08-28 18:38:37 +08:00
|
|
|
} else {
|
|
|
|
scsicmd->result = DID_ERROR << 16
|
|
|
|
| COMMAND_COMPLETE << 8;
|
|
|
|
break;
|
|
|
|
}
|
2010-05-10 19:17:57 +08:00
|
|
|
} else {
|
|
|
|
scsicmd->result = DID_ERROR << 16
|
2015-08-28 18:38:37 +08:00
|
|
|
| COMMAND_COMPLETE << 8;
|
2010-05-10 19:17:57 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-08-28 18:38:37 +08:00
|
|
|
if (le32_to_cpu(srbreply->scsi_status)
|
|
|
|
== SAM_STAT_CHECK_CONDITION) {
|
|
|
|
int len;
|
|
|
|
|
|
|
|
scsicmd->result |= SAM_STAT_CHECK_CONDITION;
|
|
|
|
len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
|
|
|
|
SCSI_SENSE_BUFFERSIZE);
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef AAC_DETAILED_STATUS_INFO
|
2015-08-28 18:38:37 +08:00
|
|
|
printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
|
|
|
|
le32_to_cpu(srbreply->status), len);
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|
2015-08-28 18:38:37 +08:00
|
|
|
memcpy(scsicmd->sense_buffer,
|
|
|
|
srbreply->sense_data, len);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* OR in the scsi status (already shifted up a bit)
|
|
|
|
*/
|
|
|
|
scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
aac_fib_complete(fibptr);
|
|
|
|
aac_fib_free(fibptr);
|
2005-10-25 01:52:22 +08:00
|
|
|
scsicmd->scsi_done(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* aac_send_scb_fib
|
|
|
|
* @scsicmd: the scsi command block
|
|
|
|
*
|
2008-01-16 23:39:06 +08:00
|
|
|
* This routine will form a FIB and fill in the aac_srb from the
|
2005-04-17 06:20:36 +08:00
|
|
|
* scsicmd passed in.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
|
|
|
|
{
|
|
|
|
struct fib* cmd_fibcontext;
|
|
|
|
struct aac_dev* dev;
|
|
|
|
int status;
|
|
|
|
|
2005-06-21 02:55:24 +08:00
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
2006-03-28 01:43:25 +08:00
|
|
|
if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
|
2005-06-21 02:55:24 +08:00
|
|
|
scsicmd->device->lun > 7) {
|
2005-04-17 06:20:36 +08:00
|
|
|
scsicmd->result = DID_NO_CONNECT << 16;
|
|
|
|
scsicmd->scsi_done(scsicmd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate and initialize a Fib then setup a BlockWrite command
|
|
|
|
*/
|
2006-02-02 01:30:55 +08:00
|
|
|
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
|
2005-04-17 06:20:36 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2007-01-24 07:00:30 +08:00
|
|
|
status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check that the command queued to the controller
|
|
|
|
*/
|
2006-03-28 01:43:40 +08:00
|
|
|
if (status == -EINPROGRESS) {
|
|
|
|
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-02 01:30:55 +08:00
|
|
|
printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
|
|
|
|
aac_fib_complete(cmd_fibcontext);
|
|
|
|
aac_fib_free(cmd_fibcontext);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct aac_dev *dev;
|
|
|
|
unsigned long byte_count = 0;
|
2007-05-26 01:00:42 +08:00
|
|
|
int nseg;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
// Get rid of old data
|
|
|
|
psg->count = 0;
|
|
|
|
psg->sg[0].addr = 0;
|
2007-05-26 01:00:42 +08:00
|
|
|
psg->sg[0].count = 0;
|
|
|
|
|
|
|
|
nseg = scsi_dma_map(scsicmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
if (nseg < 0)
|
|
|
|
return nseg;
|
2007-05-26 01:00:42 +08:00
|
|
|
if (nseg) {
|
2005-04-17 06:20:36 +08:00
|
|
|
struct scatterlist *sg;
|
|
|
|
int i;
|
|
|
|
|
2007-05-26 01:00:42 +08:00
|
|
|
psg->count = cpu_to_le32(nseg);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-26 01:00:42 +08:00
|
|
|
scsi_for_each_sg(scsicmd, sg, nseg, i) {
|
2005-04-17 06:20:36 +08:00
|
|
|
psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
|
|
|
|
psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
|
|
|
|
byte_count += sg_dma_len(sg);
|
|
|
|
}
|
|
|
|
/* hba wants the size to be exact */
|
2007-05-26 01:00:42 +08:00
|
|
|
if (byte_count > scsi_bufflen(scsicmd)) {
|
|
|
|
u32 temp = le32_to_cpu(psg->sg[i-1].count) -
|
|
|
|
(byte_count - scsi_bufflen(scsicmd));
|
2005-04-27 21:05:51 +08:00
|
|
|
psg->sg[i-1].count = cpu_to_le32(temp);
|
2007-05-26 01:00:42 +08:00
|
|
|
byte_count = scsi_bufflen(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
/* Check for command underflow */
|
|
|
|
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
|
|
|
|
printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
|
|
|
|
byte_count, scsicmd->underflow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return byte_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct aac_dev *dev;
|
|
|
|
unsigned long byte_count = 0;
|
2005-04-27 21:05:51 +08:00
|
|
|
u64 addr;
|
2007-05-26 01:00:42 +08:00
|
|
|
int nseg;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
|
|
|
|
// Get rid of old data
|
|
|
|
psg->count = 0;
|
|
|
|
psg->sg[0].addr[0] = 0;
|
|
|
|
psg->sg[0].addr[1] = 0;
|
|
|
|
psg->sg[0].count = 0;
|
2007-05-26 01:00:42 +08:00
|
|
|
|
|
|
|
nseg = scsi_dma_map(scsicmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
if (nseg < 0)
|
|
|
|
return nseg;
|
2007-05-26 01:00:42 +08:00
|
|
|
if (nseg) {
|
2005-04-17 06:20:36 +08:00
|
|
|
struct scatterlist *sg;
|
|
|
|
int i;
|
|
|
|
|
2007-05-26 01:00:42 +08:00
|
|
|
scsi_for_each_sg(scsicmd, sg, nseg, i) {
|
2006-03-28 01:44:23 +08:00
|
|
|
int count = sg_dma_len(sg);
|
2005-04-27 21:05:51 +08:00
|
|
|
addr = sg_dma_address(sg);
|
|
|
|
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
|
|
|
|
psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
|
2006-03-28 01:44:23 +08:00
|
|
|
psg->sg[i].count = cpu_to_le32(count);
|
|
|
|
byte_count += count;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-05-26 01:00:42 +08:00
|
|
|
psg->count = cpu_to_le32(nseg);
|
2005-04-17 06:20:36 +08:00
|
|
|
/* hba wants the size to be exact */
|
2007-05-26 01:00:42 +08:00
|
|
|
if (byte_count > scsi_bufflen(scsicmd)) {
|
|
|
|
u32 temp = le32_to_cpu(psg->sg[i-1].count) -
|
|
|
|
(byte_count - scsi_bufflen(scsicmd));
|
2005-04-27 21:05:51 +08:00
|
|
|
psg->sg[i-1].count = cpu_to_le32(temp);
|
2007-05-26 01:00:42 +08:00
|
|
|
byte_count = scsi_bufflen(scsicmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
/* Check for command underflow */
|
|
|
|
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
|
|
|
|
printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
|
|
|
|
byte_count, scsicmd->underflow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return byte_count;
|
|
|
|
}
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg)
|
2005-08-04 06:39:49 +08:00
|
|
|
{
|
|
|
|
unsigned long byte_count = 0;
|
2007-05-26 01:00:42 +08:00
|
|
|
int nseg;
|
2005-08-04 06:39:49 +08:00
|
|
|
|
|
|
|
// Get rid of old data
|
|
|
|
psg->count = 0;
|
|
|
|
psg->sg[0].next = 0;
|
|
|
|
psg->sg[0].prev = 0;
|
|
|
|
psg->sg[0].addr[0] = 0;
|
|
|
|
psg->sg[0].addr[1] = 0;
|
|
|
|
psg->sg[0].count = 0;
|
|
|
|
psg->sg[0].flags = 0;
|
2007-05-26 01:00:42 +08:00
|
|
|
|
|
|
|
nseg = scsi_dma_map(scsicmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
if (nseg < 0)
|
|
|
|
return nseg;
|
2007-05-26 01:00:42 +08:00
|
|
|
if (nseg) {
|
2005-08-04 06:39:49 +08:00
|
|
|
struct scatterlist *sg;
|
|
|
|
int i;
|
|
|
|
|
2007-05-26 01:00:42 +08:00
|
|
|
scsi_for_each_sg(scsicmd, sg, nseg, i) {
|
2005-08-04 06:39:49 +08:00
|
|
|
int count = sg_dma_len(sg);
|
|
|
|
u64 addr = sg_dma_address(sg);
|
|
|
|
psg->sg[i].next = 0;
|
|
|
|
psg->sg[i].prev = 0;
|
|
|
|
psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32));
|
|
|
|
psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
|
|
|
|
psg->sg[i].count = cpu_to_le32(count);
|
|
|
|
psg->sg[i].flags = 0;
|
|
|
|
byte_count += count;
|
|
|
|
}
|
2007-05-26 01:00:42 +08:00
|
|
|
psg->count = cpu_to_le32(nseg);
|
2005-08-04 06:39:49 +08:00
|
|
|
/* hba wants the size to be exact */
|
2007-05-26 01:00:42 +08:00
|
|
|
if (byte_count > scsi_bufflen(scsicmd)) {
|
|
|
|
u32 temp = le32_to_cpu(psg->sg[i-1].count) -
|
|
|
|
(byte_count - scsi_bufflen(scsicmd));
|
2005-08-04 06:39:49 +08:00
|
|
|
psg->sg[i-1].count = cpu_to_le32(temp);
|
2007-05-26 01:00:42 +08:00
|
|
|
byte_count = scsi_bufflen(scsicmd);
|
2005-08-04 06:39:49 +08:00
|
|
|
}
|
|
|
|
/* Check for command underflow */
|
|
|
|
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
|
|
|
|
printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
|
|
|
|
byte_count, scsicmd->underflow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return byte_count;
|
|
|
|
}
|
|
|
|
|
2012-10-19 21:51:07 +08:00
|
|
|
static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
|
|
|
|
struct aac_raw_io2 *rio2, int sg_max)
|
2012-07-14 20:48:51 +08:00
|
|
|
{
|
|
|
|
unsigned long byte_count = 0;
|
|
|
|
int nseg;
|
|
|
|
|
|
|
|
nseg = scsi_dma_map(scsicmd);
|
2012-10-19 21:51:07 +08:00
|
|
|
if (nseg < 0)
|
|
|
|
return nseg;
|
2012-07-14 20:48:51 +08:00
|
|
|
if (nseg) {
|
|
|
|
struct scatterlist *sg;
|
|
|
|
int i, conformable = 0;
|
|
|
|
u32 min_size = PAGE_SIZE, cur_size;
|
|
|
|
|
|
|
|
scsi_for_each_sg(scsicmd, sg, nseg, i) {
|
|
|
|
int count = sg_dma_len(sg);
|
|
|
|
u64 addr = sg_dma_address(sg);
|
|
|
|
|
|
|
|
BUG_ON(i >= sg_max);
|
|
|
|
rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32));
|
|
|
|
rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff));
|
|
|
|
cur_size = cpu_to_le32(count);
|
|
|
|
rio2->sge[i].length = cur_size;
|
|
|
|
rio2->sge[i].flags = 0;
|
|
|
|
if (i == 0) {
|
|
|
|
conformable = 1;
|
|
|
|
rio2->sgeFirstSize = cur_size;
|
|
|
|
} else if (i == 1) {
|
|
|
|
rio2->sgeNominalSize = cur_size;
|
|
|
|
min_size = cur_size;
|
|
|
|
} else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) {
|
|
|
|
conformable = 0;
|
|
|
|
if (cur_size < min_size)
|
|
|
|
min_size = cur_size;
|
|
|
|
}
|
|
|
|
byte_count += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* hba wants the size to be exact */
|
|
|
|
if (byte_count > scsi_bufflen(scsicmd)) {
|
|
|
|
u32 temp = le32_to_cpu(rio2->sge[i-1].length) -
|
|
|
|
(byte_count - scsi_bufflen(scsicmd));
|
|
|
|
rio2->sge[i-1].length = cpu_to_le32(temp);
|
|
|
|
byte_count = scsi_bufflen(scsicmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
rio2->sgeCnt = cpu_to_le32(nseg);
|
|
|
|
rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212);
|
|
|
|
/* not conformable: evaluate required sg elements */
|
|
|
|
if (!conformable) {
|
|
|
|
int j, nseg_new = nseg, err_found;
|
|
|
|
for (i = min_size / PAGE_SIZE; i >= 1; --i) {
|
|
|
|
err_found = 0;
|
|
|
|
nseg_new = 2;
|
|
|
|
for (j = 1; j < nseg - 1; ++j) {
|
|
|
|
if (rio2->sge[j].length % (i*PAGE_SIZE)) {
|
|
|
|
err_found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE));
|
|
|
|
}
|
|
|
|
if (!err_found)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i > 0 && nseg_new <= sg_max)
|
|
|
|
aac_convert_sgraw2(rio2, i, nseg, nseg_new);
|
|
|
|
} else
|
|
|
|
rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
|
|
|
|
|
|
|
|
/* Check for command underflow */
|
|
|
|
if (scsicmd->underflow && (byte_count < scsicmd->underflow)) {
|
|
|
|
printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
|
|
|
|
byte_count, scsicmd->underflow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return byte_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new)
|
|
|
|
{
|
|
|
|
struct sge_ieee1212 *sge;
|
|
|
|
int i, j, pos;
|
|
|
|
u32 addr_low;
|
|
|
|
|
|
|
|
if (aac_convert_sgl == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC);
|
|
|
|
if (sge == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 1, pos = 1; i < nseg-1; ++i) {
|
|
|
|
for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) {
|
|
|
|
addr_low = rio2->sge[i].addrLow + j * pages * PAGE_SIZE;
|
|
|
|
sge[pos].addrLow = addr_low;
|
|
|
|
sge[pos].addrHigh = rio2->sge[i].addrHigh;
|
|
|
|
if (addr_low < rio2->sge[i].addrLow)
|
|
|
|
sge[pos].addrHigh++;
|
|
|
|
sge[pos].length = pages * PAGE_SIZE;
|
|
|
|
sge[pos].flags = 0;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sge[pos] = rio2->sge[nseg-1];
|
|
|
|
memcpy(&rio2->sge[1], &sge[1], (nseg_new-1)*sizeof(struct sge_ieee1212));
|
|
|
|
|
|
|
|
kfree(sge);
|
|
|
|
rio2->sgeCnt = cpu_to_le32(nseg_new);
|
|
|
|
rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT);
|
|
|
|
rio2->sgeNominalSize = pages * PAGE_SIZE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
#ifdef AAC_DETAILED_STATUS_INFO
|
|
|
|
|
|
|
|
struct aac_srb_status_info {
|
|
|
|
u32 status;
|
|
|
|
char *str;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct aac_srb_status_info srb_status_info[] = {
|
|
|
|
{ SRB_STATUS_PENDING, "Pending Status"},
|
|
|
|
{ SRB_STATUS_SUCCESS, "Success"},
|
|
|
|
{ SRB_STATUS_ABORTED, "Aborted Command"},
|
|
|
|
{ SRB_STATUS_ABORT_FAILED, "Abort Failed"},
|
2006-06-09 13:23:48 +08:00
|
|
|
{ SRB_STATUS_ERROR, "Error Event"},
|
2005-04-17 06:20:36 +08:00
|
|
|
{ SRB_STATUS_BUSY, "Device Busy"},
|
|
|
|
{ SRB_STATUS_INVALID_REQUEST, "Invalid Request"},
|
|
|
|
{ SRB_STATUS_INVALID_PATH_ID, "Invalid Path ID"},
|
|
|
|
{ SRB_STATUS_NO_DEVICE, "No Device"},
|
|
|
|
{ SRB_STATUS_TIMEOUT, "Timeout"},
|
|
|
|
{ SRB_STATUS_SELECTION_TIMEOUT, "Selection Timeout"},
|
|
|
|
{ SRB_STATUS_COMMAND_TIMEOUT, "Command Timeout"},
|
|
|
|
{ SRB_STATUS_MESSAGE_REJECTED, "Message Rejected"},
|
|
|
|
{ SRB_STATUS_BUS_RESET, "Bus Reset"},
|
|
|
|
{ SRB_STATUS_PARITY_ERROR, "Parity Error"},
|
|
|
|
{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
|
|
|
|
{ SRB_STATUS_NO_HBA, "No HBA"},
|
|
|
|
{ SRB_STATUS_DATA_OVERRUN, "Data Overrun/Data Underrun"},
|
|
|
|
{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
|
|
|
|
{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
|
|
|
|
{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
|
|
|
|
{ SRB_STATUS_REQUEST_FLUSHED, "Request Flushed"},
|
|
|
|
{ SRB_STATUS_DELAYED_RETRY, "Delayed Retry"},
|
2006-06-09 13:23:48 +08:00
|
|
|
{ SRB_STATUS_INVALID_LUN, "Invalid LUN"},
|
2005-04-17 06:20:36 +08:00
|
|
|
{ SRB_STATUS_INVALID_TARGET_ID, "Invalid TARGET ID"},
|
|
|
|
{ SRB_STATUS_BAD_FUNCTION, "Bad Function"},
|
|
|
|
{ SRB_STATUS_ERROR_RECOVERY, "Error Recovery"},
|
|
|
|
{ SRB_STATUS_NOT_STARTED, "Not Started"},
|
|
|
|
{ SRB_STATUS_NOT_IN_USE, "Not In Use"},
|
2008-01-16 23:39:06 +08:00
|
|
|
{ SRB_STATUS_FORCE_ABORT, "Force Abort"},
|
2005-04-17 06:20:36 +08:00
|
|
|
{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
|
|
|
|
{ 0xff, "Unknown Error"}
|
|
|
|
};
|
|
|
|
|
|
|
|
char *aac_get_status_string(u32 status)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2006-06-09 13:23:48 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(srb_status_info); i++)
|
|
|
|
if (srb_status_info[i].status == status)
|
2005-04-17 06:20:36 +08:00
|
|
|
return srb_status_info[i].str;
|
|
|
|
|
|
|
|
return "Bad Status Code";
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|