11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Adaptec AAC series RAID controller driver 3fa195afeSAlan Cox * (c) Copyright 2001 Red Hat Inc. 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * based on the old aacraid driver that is.. 61da177e4SLinus Torvalds * Adaptec aacraid device driver for Linux. 71da177e4SLinus Torvalds * 8e8b12f0fSMahesh Rajashekhara * Copyright (c) 2000-2010 Adaptec, Inc. 9e8b12f0fSMahesh Rajashekhara * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 121da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 131da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 141da177e4SLinus Torvalds * any later version. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 171da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 181da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191da177e4SLinus Torvalds * GNU General Public License for more details. 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 221da177e4SLinus Torvalds * along with this program; see the file COPYING. If not, write to 231da177e4SLinus Torvalds * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <linux/kernel.h> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/pci.h> 311da177e4SLinus Torvalds #include <linux/spinlock.h> 321da177e4SLinus Torvalds #include <linux/slab.h> 331da177e4SLinus Torvalds #include <linux/completion.h> 341da177e4SLinus Torvalds #include <linux/blkdev.h> 357c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 363a0086a8SSalyzyn, Mark #include <linux/highmem.h> /* For flush_kernel_dcache_page */ 37acf3368fSPaul Gortmaker #include <linux/module.h> 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #include <scsi/scsi.h> 401da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h> 411da177e4SLinus Torvalds #include <scsi/scsi_device.h> 421da177e4SLinus Torvalds #include <scsi/scsi_host.h> 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #include "aacraid.h" 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* values for inqd_pdt: Peripheral device type in plain English */ 471da177e4SLinus Torvalds #define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ 481da177e4SLinus Torvalds #define INQD_PDT_PROC 0x03 /* Processor device */ 491da177e4SLinus Torvalds #define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ 501da177e4SLinus Torvalds #define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ 511da177e4SLinus Torvalds #define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ 521da177e4SLinus Torvalds #define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds #define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ 551da177e4SLinus Torvalds #define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * Sense codes 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #define SENCODE_NO_SENSE 0x00 621da177e4SLinus Torvalds #define SENCODE_END_OF_DATA 0x00 631da177e4SLinus Torvalds #define SENCODE_BECOMING_READY 0x04 641da177e4SLinus Torvalds #define SENCODE_INIT_CMD_REQUIRED 0x04 65f956a669SRaghava Aditya Renukunta #define SENCODE_UNRECOVERED_READ_ERROR 0x11 661da177e4SLinus Torvalds #define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A 671da177e4SLinus Torvalds #define SENCODE_INVALID_COMMAND 0x20 681da177e4SLinus Torvalds #define SENCODE_LBA_OUT_OF_RANGE 0x21 691da177e4SLinus Torvalds #define SENCODE_INVALID_CDB_FIELD 0x24 701da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SUPPORTED 0x25 711da177e4SLinus Torvalds #define SENCODE_INVALID_PARAM_FIELD 0x26 721da177e4SLinus Torvalds #define SENCODE_PARAM_NOT_SUPPORTED 0x26 731da177e4SLinus Torvalds #define SENCODE_PARAM_VALUE_INVALID 0x26 741da177e4SLinus Torvalds #define SENCODE_RESET_OCCURRED 0x29 751da177e4SLinus Torvalds #define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E 761da177e4SLinus Torvalds #define SENCODE_INQUIRY_DATA_CHANGED 0x3F 771da177e4SLinus Torvalds #define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 781da177e4SLinus Torvalds #define SENCODE_DIAGNOSTIC_FAILURE 0x40 791da177e4SLinus Torvalds #define SENCODE_INTERNAL_TARGET_FAILURE 0x44 801da177e4SLinus Torvalds #define SENCODE_INVALID_MESSAGE_ERROR 0x49 811da177e4SLinus Torvalds #define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c 821da177e4SLinus Torvalds #define SENCODE_OVERLAPPED_COMMAND 0x4E 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* 851da177e4SLinus Torvalds * Additional sense codes 861da177e4SLinus Torvalds */ 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds #define ASENCODE_NO_SENSE 0x00 891da177e4SLinus Torvalds #define ASENCODE_END_OF_DATA 0x05 901da177e4SLinus Torvalds #define ASENCODE_BECOMING_READY 0x01 911da177e4SLinus Torvalds #define ASENCODE_INIT_CMD_REQUIRED 0x02 921da177e4SLinus Torvalds #define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 931da177e4SLinus Torvalds #define ASENCODE_INVALID_COMMAND 0x00 941da177e4SLinus Torvalds #define ASENCODE_LBA_OUT_OF_RANGE 0x00 951da177e4SLinus Torvalds #define ASENCODE_INVALID_CDB_FIELD 0x00 961da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SUPPORTED 0x00 971da177e4SLinus Torvalds #define ASENCODE_INVALID_PARAM_FIELD 0x00 981da177e4SLinus Torvalds #define ASENCODE_PARAM_NOT_SUPPORTED 0x01 991da177e4SLinus Torvalds #define ASENCODE_PARAM_VALUE_INVALID 0x02 1001da177e4SLinus Torvalds #define ASENCODE_RESET_OCCURRED 0x00 1011da177e4SLinus Torvalds #define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 1021da177e4SLinus Torvalds #define ASENCODE_INQUIRY_DATA_CHANGED 0x03 1031da177e4SLinus Torvalds #define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 1041da177e4SLinus Torvalds #define ASENCODE_DIAGNOSTIC_FAILURE 0x80 1051da177e4SLinus Torvalds #define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 1061da177e4SLinus Torvalds #define ASENCODE_INVALID_MESSAGE_ERROR 0x00 1071da177e4SLinus Torvalds #define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 1081da177e4SLinus Torvalds #define ASENCODE_OVERLAPPED_COMMAND 0x00 1091da177e4SLinus Torvalds 110c4e2fbcaSRaghava Aditya Renukunta #define AAC_STAT_GOOD (DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD) 111c4e2fbcaSRaghava Aditya Renukunta 1121da177e4SLinus Torvalds #define BYTE0(x) (unsigned char)(x) 1131da177e4SLinus Torvalds #define BYTE1(x) (unsigned char)((x) >> 8) 1141da177e4SLinus Torvalds #define BYTE2(x) (unsigned char)((x) >> 16) 1151da177e4SLinus Torvalds #define BYTE3(x) (unsigned char)((x) >> 24) 1161da177e4SLinus Torvalds 117b836439fSMahesh Rajashekhara /* MODE_SENSE data format */ 118b836439fSMahesh Rajashekhara typedef struct { 119b836439fSMahesh Rajashekhara struct { 120b836439fSMahesh Rajashekhara u8 data_length; 121b836439fSMahesh Rajashekhara u8 med_type; 122b836439fSMahesh Rajashekhara u8 dev_par; 123b836439fSMahesh Rajashekhara u8 bd_length; 124b836439fSMahesh Rajashekhara } __attribute__((packed)) hd; 125b836439fSMahesh Rajashekhara struct { 126b836439fSMahesh Rajashekhara u8 dens_code; 127b836439fSMahesh Rajashekhara u8 block_count[3]; 128b836439fSMahesh Rajashekhara u8 reserved; 129b836439fSMahesh Rajashekhara u8 block_length[3]; 130b836439fSMahesh Rajashekhara } __attribute__((packed)) bd; 131b836439fSMahesh Rajashekhara u8 mpc_buf[3]; 132b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep_data; 133b836439fSMahesh Rajashekhara 134b836439fSMahesh Rajashekhara /* MODE_SENSE_10 data format */ 135b836439fSMahesh Rajashekhara typedef struct { 136b836439fSMahesh Rajashekhara struct { 137b836439fSMahesh Rajashekhara u8 data_length[2]; 138b836439fSMahesh Rajashekhara u8 med_type; 139b836439fSMahesh Rajashekhara u8 dev_par; 140b836439fSMahesh Rajashekhara u8 rsrvd[2]; 141b836439fSMahesh Rajashekhara u8 bd_length[2]; 142b836439fSMahesh Rajashekhara } __attribute__((packed)) hd; 143b836439fSMahesh Rajashekhara struct { 144b836439fSMahesh Rajashekhara u8 dens_code; 145b836439fSMahesh Rajashekhara u8 block_count[3]; 146b836439fSMahesh Rajashekhara u8 reserved; 147b836439fSMahesh Rajashekhara u8 block_length[3]; 148b836439fSMahesh Rajashekhara } __attribute__((packed)) bd; 149b836439fSMahesh Rajashekhara u8 mpc_buf[3]; 150b836439fSMahesh Rajashekhara } __attribute__((packed)) aac_modep10_data; 151b836439fSMahesh Rajashekhara 1521da177e4SLinus Torvalds /*------------------------------------------------------------------------------ 1531da177e4SLinus Torvalds * S T R U C T S / T Y P E D E F S 1541da177e4SLinus Torvalds *----------------------------------------------------------------------------*/ 1551da177e4SLinus Torvalds /* SCSI inquiry data */ 1561da177e4SLinus Torvalds struct inquiry_data { 1571da177e4SLinus Torvalds u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ 1581da177e4SLinus Torvalds u8 inqd_dtq; /* RMB | Device Type Qualifier */ 1591da177e4SLinus Torvalds u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ 1601da177e4SLinus Torvalds u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ 1611da177e4SLinus Torvalds u8 inqd_len; /* Additional length (n-4) */ 1621da177e4SLinus Torvalds u8 inqd_pad1[2];/* Reserved - must be zero */ 1631da177e4SLinus Torvalds u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ 1641da177e4SLinus Torvalds u8 inqd_vid[8]; /* Vendor ID */ 1651da177e4SLinus Torvalds u8 inqd_pid[16];/* Product ID */ 1661da177e4SLinus Torvalds u8 inqd_prl[4]; /* Product Revision Level */ 1671da177e4SLinus Torvalds }; 1681da177e4SLinus Torvalds 1695d910649SMahesh Rajashekhara /* Added for VPD 0x83 */ 1705d910649SMahesh Rajashekhara typedef struct { 1715d910649SMahesh Rajashekhara u8 CodeSet:4; /* VPD_CODE_SET */ 1725d910649SMahesh Rajashekhara u8 Reserved:4; 1735d910649SMahesh Rajashekhara u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */ 1745d910649SMahesh Rajashekhara u8 Reserved2:4; 1755d910649SMahesh Rajashekhara u8 Reserved3; 1765d910649SMahesh Rajashekhara u8 IdentifierLength; 1775d910649SMahesh Rajashekhara u8 VendId[8]; 1785d910649SMahesh Rajashekhara u8 ProductId[16]; 1795d910649SMahesh Rajashekhara u8 SerialNumber[8]; /* SN in ASCII */ 1805d910649SMahesh Rajashekhara 1815d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_1; 1825d910649SMahesh Rajashekhara 1835d910649SMahesh Rajashekhara typedef struct { 1845d910649SMahesh Rajashekhara u8 CodeSet:4; /* VPD_CODE_SET */ 1855d910649SMahesh Rajashekhara u8 Reserved:4; 1865d910649SMahesh Rajashekhara u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */ 1875d910649SMahesh Rajashekhara u8 Reserved2:4; 1885d910649SMahesh Rajashekhara u8 Reserved3; 1895d910649SMahesh Rajashekhara u8 IdentifierLength; 1905d910649SMahesh Rajashekhara struct TEU64Id { 1915d910649SMahesh Rajashekhara u32 Serial; 1925d910649SMahesh Rajashekhara /* The serial number supposed to be 40 bits, 1935d910649SMahesh Rajashekhara * bit we only support 32, so make the last byte zero. */ 1945d910649SMahesh Rajashekhara u8 Reserved; 1955d910649SMahesh Rajashekhara u8 VendId[3]; 1965d910649SMahesh Rajashekhara } EU64Id; 1975d910649SMahesh Rajashekhara 1985d910649SMahesh Rajashekhara } TVPD_ID_Descriptor_Type_2; 1995d910649SMahesh Rajashekhara 2005d910649SMahesh Rajashekhara typedef struct { 2015d910649SMahesh Rajashekhara u8 DeviceType:5; 2025d910649SMahesh Rajashekhara u8 DeviceTypeQualifier:3; 2035d910649SMahesh Rajashekhara u8 PageCode; 2045d910649SMahesh Rajashekhara u8 Reserved; 2055d910649SMahesh Rajashekhara u8 PageLength; 2065d910649SMahesh Rajashekhara TVPD_ID_Descriptor_Type_1 IdDescriptorType1; 2075d910649SMahesh Rajashekhara TVPD_ID_Descriptor_Type_2 IdDescriptorType2; 2085d910649SMahesh Rajashekhara 2095d910649SMahesh Rajashekhara } TVPD_Page83; 2105d910649SMahesh Rajashekhara 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * M O D U L E G L O B A L S 2131da177e4SLinus Torvalds */ 2141da177e4SLinus Torvalds 2150b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap); 2160b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg); 2170b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg); 2180b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd, 2190b433447SMahesh Rajashekhara struct aac_raw_io2 *rio2, int sg_max); 220ab5d129fSRaghava Aditya Renukunta static long aac_build_sghba(struct scsi_cmnd *scsicmd, 221ab5d129fSRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd, 222ab5d129fSRaghava Aditya Renukunta int sg_max, u64 sg_address); 2230b433447SMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, 2240b433447SMahesh Rajashekhara int pages, int nseg, int nseg_new); 2251da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); 226ab5d129fSRaghava Aditya Renukunta static int aac_send_hba_fib(struct scsi_cmnd *scsicmd); 2271da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO 2281da177e4SLinus Torvalds static char *aac_get_status_string(u32 status); 2291da177e4SLinus Torvalds #endif 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds /* 2321da177e4SLinus Torvalds * Non dasd selection is handled entirely in aachba now 2331da177e4SLinus Torvalds */ 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static int nondasd = -1; 236d8e96507SLeubner, Achim static int aac_cache = 2; /* WCE=0 to avoid performance problems */ 2371da177e4SLinus Torvalds static int dacmode = -1; 2388ef22247SSalyzyn, Mark int aac_msi; 2391208bab5SSalyzyn, Mark int aac_commit = -1; 240404d9a90SMark Haverkamp int startup_timeout = 180; 241404d9a90SMark Haverkamp int aif_timeout = 120; 24211604612SMahesh Rajashekhara int aac_sync_mode; /* Only Sync. transfer - disabled */ 24385d22bbfSMahesh Rajashekhara int aac_convert_sgl = 1; /* convert non-conformable s/g list - enabled */ 2441da177e4SLinus Torvalds 24511604612SMahesh Rajashekhara module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR); 24611604612SMahesh Rajashekhara MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode" 24711604612SMahesh Rajashekhara " 0=off, 1=on"); 24885d22bbfSMahesh Rajashekhara module_param(aac_convert_sgl, int, S_IRUGO|S_IWUSR); 24985d22bbfSMahesh Rajashekhara MODULE_PARM_DESC(aac_convert_sgl, "Convert non-conformable s/g list" 25085d22bbfSMahesh Rajashekhara " 0=off, 1=on"); 2519a72f976SMark Haverkamp module_param(nondasd, int, S_IRUGO|S_IWUSR); 2528ef22247SSalyzyn, Mark MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices." 2538ef22247SSalyzyn, Mark " 0=off, 1=on"); 25495e852e1SSalyzyn, Mark module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); 2558ef22247SSalyzyn, Mark MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n" 2568ef22247SSalyzyn, Mark "\tbit 0 - Disable FUA in WRITE SCSI commands\n" 2578ef22247SSalyzyn, Mark "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n" 258d8e96507SLeubner, Achim "\tbit 2 - Disable only if Battery is protecting Cache"); 2599a72f976SMark Haverkamp module_param(dacmode, int, S_IRUGO|S_IWUSR); 2608ef22247SSalyzyn, Mark MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC." 2618ef22247SSalyzyn, Mark " 0=off, 1=on"); 2621208bab5SSalyzyn, Mark module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); 2638ef22247SSalyzyn, Mark MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" 2648ef22247SSalyzyn, Mark " adapter for foreign arrays.\n" 2658ef22247SSalyzyn, Mark "This is typically needed in systems that do not have a BIOS." 2668ef22247SSalyzyn, Mark " 0=off, 1=on"); 2678ef22247SSalyzyn, Mark module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); 2688ef22247SSalyzyn, Mark MODULE_PARM_DESC(msi, "IRQ handling." 2699022d375SMahesh Rajashekhara " 0=PIC(default), 1=MSI, 2=MSI-X)"); 270404d9a90SMark Haverkamp module_param(startup_timeout, int, S_IRUGO|S_IWUSR); 2718ef22247SSalyzyn, Mark MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" 2728ef22247SSalyzyn, Mark " adapter to have it's kernel up and\n" 2738ef22247SSalyzyn, Mark "running. This is typically adjusted for large systems that do not" 2748ef22247SSalyzyn, Mark " have a BIOS."); 275404d9a90SMark Haverkamp module_param(aif_timeout, int, S_IRUGO|S_IWUSR); 2768ef22247SSalyzyn, Mark MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for" 2778ef22247SSalyzyn, Mark " applications to pick up AIFs before\n" 2788ef22247SSalyzyn, Mark "deregistering them. This is typically adjusted for heavily burdened" 2798ef22247SSalyzyn, Mark " systems."); 2801da177e4SLinus Torvalds 2817c00ffa3SMark Haverkamp int numacb = -1; 2827c00ffa3SMark Haverkamp module_param(numacb, int, S_IRUGO|S_IWUSR); 2838ef22247SSalyzyn, Mark MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control" 2848ef22247SSalyzyn, Mark " blocks (FIB) allocated. Valid values are 512 and down. Default is" 2858ef22247SSalyzyn, Mark " to use suggestion from Firmware."); 2867c00ffa3SMark Haverkamp 2877c00ffa3SMark Haverkamp int acbsize = -1; 2887c00ffa3SMark Haverkamp module_param(acbsize, int, S_IRUGO|S_IWUSR); 2898ef22247SSalyzyn, Mark MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)" 2908ef22247SSalyzyn, Mark " size. Valid values are 512, 2048, 4096 and 8192. Default is to use" 2918ef22247SSalyzyn, Mark " suggestion from Firmware."); 292653ba58dSMark Haverkamp 29329c97684SSalyzyn, Mark int update_interval = 30 * 60; 29429c97684SSalyzyn, Mark module_param(update_interval, int, S_IRUGO|S_IWUSR); 2958ef22247SSalyzyn, Mark MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync" 2968ef22247SSalyzyn, Mark " updates issued to adapter."); 29729c97684SSalyzyn, Mark 29829c97684SSalyzyn, Mark int check_interval = 24 * 60 * 60; 29929c97684SSalyzyn, Mark module_param(check_interval, int, S_IRUGO|S_IWUSR); 3008ef22247SSalyzyn, Mark MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" 3018ef22247SSalyzyn, Mark " checks."); 30229c97684SSalyzyn, Mark 30387f3bda3SAndrew Morton int aac_check_reset = 1; 30487f3bda3SAndrew Morton module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); 30595e7a8efSPaul Bolle MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the" 3068ef22247SSalyzyn, Mark " adapter. a value of -1 forces the reset to adapters programmed to" 3078ef22247SSalyzyn, Mark " ignore it."); 30829c97684SSalyzyn, Mark 309e37ee4beSMark Haverkamp int expose_physicals = -1; 310653ba58dSMark Haverkamp module_param(expose_physicals, int, S_IRUGO|S_IWUSR); 3118ef22247SSalyzyn, Mark MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays." 3128ef22247SSalyzyn, Mark " -1=protect 0=off, 1=on"); 31303d44337SMark Haverkamp 3148ef22247SSalyzyn, Mark int aac_reset_devices; 3151208bab5SSalyzyn, Mark module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); 3161208bab5SSalyzyn, Mark MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); 31703d44337SMark Haverkamp 318d8e96507SLeubner, Achim int aac_wwn = 1; 319d8e96507SLeubner, Achim module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR); 320d8e96507SLeubner, Achim MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n" 321d8e96507SLeubner, Achim "\t0 - Disable\n" 322d8e96507SLeubner, Achim "\t1 - Array Meta Data Signature (default)\n" 323d8e96507SLeubner, Achim "\t2 - Adapter Serial Number"); 324d8e96507SLeubner, Achim 325d8e96507SLeubner, Achim 32603d44337SMark Haverkamp static inline int aac_valid_context(struct scsi_cmnd *scsicmd, 32703d44337SMark Haverkamp struct fib *fibptr) { 32803d44337SMark Haverkamp struct scsi_device *device; 32903d44337SMark Haverkamp 33003d44337SMark Haverkamp if (unlikely(!scsicmd || !scsicmd->scsi_done)) { 331c835e372SSalyzyn, Mark dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n")); 33203d44337SMark Haverkamp aac_fib_complete(fibptr); 33303d44337SMark Haverkamp return 0; 33403d44337SMark Haverkamp } 33503d44337SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; 33603d44337SMark Haverkamp device = scsicmd->device; 3373ffd6c5aSRaghava Aditya Renukunta if (unlikely(!device)) { 33803d44337SMark Haverkamp dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n")); 33903d44337SMark Haverkamp aac_fib_complete(fibptr); 34003d44337SMark Haverkamp return 0; 34103d44337SMark Haverkamp } 34203d44337SMark Haverkamp return 1; 34303d44337SMark Haverkamp } 34403d44337SMark Haverkamp 3451da177e4SLinus Torvalds /** 3461da177e4SLinus Torvalds * aac_get_config_status - check the adapter configuration 3471da177e4SLinus Torvalds * @common: adapter to query 3481da177e4SLinus Torvalds * 3491da177e4SLinus Torvalds * Query config status, and commit the configuration if needed. 3501da177e4SLinus Torvalds */ 3518c867b25SMark Haverkamp int aac_get_config_status(struct aac_dev *dev, int commit_flag) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds int status = 0; 3541da177e4SLinus Torvalds struct fib * fibptr; 3551da177e4SLinus Torvalds 356bfb35aa8SMark Haverkamp if (!(fibptr = aac_fib_alloc(dev))) 3571da177e4SLinus Torvalds return -ENOMEM; 3581da177e4SLinus Torvalds 359bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds struct aac_get_config_status *dinfo; 3621da177e4SLinus Torvalds dinfo = (struct aac_get_config_status *) fib_data(fibptr); 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds dinfo->command = cpu_to_le32(VM_ContainerConfig); 3651da177e4SLinus Torvalds dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS); 3661da177e4SLinus Torvalds dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data)); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369bfb35aa8SMark Haverkamp status = aac_fib_send(ContainerCommand, 3701da177e4SLinus Torvalds fibptr, 3711da177e4SLinus Torvalds sizeof (struct aac_get_config_status), 3721da177e4SLinus Torvalds FsaNormal, 3731da177e4SLinus Torvalds 1, 1, 3741da177e4SLinus Torvalds NULL, NULL); 3751da177e4SLinus Torvalds if (status < 0) { 3761da177e4SLinus Torvalds printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n"); 3771da177e4SLinus Torvalds } else { 3781da177e4SLinus Torvalds struct aac_get_config_status_resp *reply 3791da177e4SLinus Torvalds = (struct aac_get_config_status_resp *) fib_data(fibptr); 3801da177e4SLinus Torvalds dprintk((KERN_WARNING 3811da177e4SLinus Torvalds "aac_get_config_status: response=%d status=%d action=%d\n", 3821da177e4SLinus Torvalds le32_to_cpu(reply->response), 3831da177e4SLinus Torvalds le32_to_cpu(reply->status), 3841da177e4SLinus Torvalds le32_to_cpu(reply->data.action))); 3851da177e4SLinus Torvalds if ((le32_to_cpu(reply->response) != ST_OK) || 3861da177e4SLinus Torvalds (le32_to_cpu(reply->status) != CT_OK) || 3871da177e4SLinus Torvalds (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) { 3881da177e4SLinus Torvalds printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n"); 3891da177e4SLinus Torvalds status = -EINVAL; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds } 392cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* Do not set XferState to zero unless receives a response from F/W */ 393cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status >= 0) 394bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 395cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 3961da177e4SLinus Torvalds /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ 3971da177e4SLinus Torvalds if (status >= 0) { 3981208bab5SSalyzyn, Mark if ((aac_commit == 1) || commit_flag) { 3991da177e4SLinus Torvalds struct aac_commit_config * dinfo; 400bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 4011da177e4SLinus Torvalds dinfo = (struct aac_commit_config *) fib_data(fibptr); 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds dinfo->command = cpu_to_le32(VM_ContainerConfig); 4041da177e4SLinus Torvalds dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG); 4051da177e4SLinus Torvalds 406bfb35aa8SMark Haverkamp status = aac_fib_send(ContainerCommand, 4071da177e4SLinus Torvalds fibptr, 4081da177e4SLinus Torvalds sizeof (struct aac_commit_config), 4091da177e4SLinus Torvalds FsaNormal, 4101da177e4SLinus Torvalds 1, 1, 4111da177e4SLinus Torvalds NULL, NULL); 412cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* Do not set XferState to zero unless 413cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech * receives a response from F/W */ 414cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status >= 0) 415bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 4161208bab5SSalyzyn, Mark } else if (aac_commit == 0) { 4171da177e4SLinus Torvalds printk(KERN_WARNING 4181da177e4SLinus Torvalds "aac_get_config_status: Foreign device configurations are being ignored\n"); 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds } 421cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* FIB should be freed only after getting the response from the F/W */ 422cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status != -ERESTARTSYS) 423bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 4241da177e4SLinus Torvalds return status; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 427e3cc268fSRajashekhara, Mahesh static void aac_expose_phy_device(struct scsi_cmnd *scsicmd) 428e3cc268fSRajashekhara, Mahesh { 429e3cc268fSRajashekhara, Mahesh char inq_data; 430e3cc268fSRajashekhara, Mahesh scsi_sg_copy_to_buffer(scsicmd, &inq_data, sizeof(inq_data)); 431e3cc268fSRajashekhara, Mahesh if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) { 432e3cc268fSRajashekhara, Mahesh inq_data &= 0xdf; 433e3cc268fSRajashekhara, Mahesh scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); 434e3cc268fSRajashekhara, Mahesh } 435e3cc268fSRajashekhara, Mahesh } 436e3cc268fSRajashekhara, Mahesh 4371da177e4SLinus Torvalds /** 4381da177e4SLinus Torvalds * aac_get_containers - list containers 4391da177e4SLinus Torvalds * @common: adapter to probe 4401da177e4SLinus Torvalds * 4411da177e4SLinus Torvalds * Make a list of all containers on this controller 4421da177e4SLinus Torvalds */ 4431da177e4SLinus Torvalds int aac_get_containers(struct aac_dev *dev) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds struct fsa_dev_info *fsa_dev_ptr; 4461da177e4SLinus Torvalds u32 index; 4471da177e4SLinus Torvalds int status = 0; 4481da177e4SLinus Torvalds struct fib * fibptr; 4491da177e4SLinus Torvalds struct aac_get_container_count *dinfo; 4501da177e4SLinus Torvalds struct aac_get_container_count_resp *dresp; 4511da177e4SLinus Torvalds int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; 4521da177e4SLinus Torvalds 453bfb35aa8SMark Haverkamp if (!(fibptr = aac_fib_alloc(dev))) 4541da177e4SLinus Torvalds return -ENOMEM; 4551da177e4SLinus Torvalds 456bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 4571da177e4SLinus Torvalds dinfo = (struct aac_get_container_count *) fib_data(fibptr); 4581da177e4SLinus Torvalds dinfo->command = cpu_to_le32(VM_ContainerConfig); 4591da177e4SLinus Torvalds dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT); 4601da177e4SLinus Torvalds 461bfb35aa8SMark Haverkamp status = aac_fib_send(ContainerCommand, 4621da177e4SLinus Torvalds fibptr, 4631da177e4SLinus Torvalds sizeof (struct aac_get_container_count), 4641da177e4SLinus Torvalds FsaNormal, 4651da177e4SLinus Torvalds 1, 1, 4661da177e4SLinus Torvalds NULL, NULL); 4671da177e4SLinus Torvalds if (status >= 0) { 4681da177e4SLinus Torvalds dresp = (struct aac_get_container_count_resp *)fib_data(fibptr); 4691da177e4SLinus Torvalds maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); 470a7129a54SMahesh Rajashekhara if (fibptr->dev->supplement_adapter_info.SupportedOptions2 & 471a7129a54SMahesh Rajashekhara AAC_OPTION_SUPPORTED_240_VOLUMES) { 472a7129a54SMahesh Rajashekhara maximum_num_containers = 473a7129a54SMahesh Rajashekhara le32_to_cpu(dresp->MaxSimpleVolumes); 474a7129a54SMahesh Rajashekhara } 475bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 4761da177e4SLinus Torvalds } 477cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* FIB should be freed only after getting the response from the F/W */ 478cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (status != -ERESTARTSYS) 479fe76df42SMark Haverkamp aac_fib_free(fibptr); 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) 4821da177e4SLinus Torvalds maximum_num_containers = MAXIMUM_NUM_CONTAINERS; 4833ffd6c5aSRaghava Aditya Renukunta if (dev->fsa_dev == NULL || 4843ffd6c5aSRaghava Aditya Renukunta dev->maximum_num_containers != maximum_num_containers) { 4853ffd6c5aSRaghava Aditya Renukunta 4863ffd6c5aSRaghava Aditya Renukunta fsa_dev_ptr = dev->fsa_dev; 4873ffd6c5aSRaghava Aditya Renukunta 4883ffd6c5aSRaghava Aditya Renukunta dev->fsa_dev = kcalloc(maximum_num_containers, 4893ffd6c5aSRaghava Aditya Renukunta sizeof(*fsa_dev_ptr), GFP_KERNEL); 4903ffd6c5aSRaghava Aditya Renukunta 4913ffd6c5aSRaghava Aditya Renukunta kfree(fsa_dev_ptr); 4923ffd6c5aSRaghava Aditya Renukunta fsa_dev_ptr = NULL; 4933ffd6c5aSRaghava Aditya Renukunta 4943ffd6c5aSRaghava Aditya Renukunta 4953ffd6c5aSRaghava Aditya Renukunta if (!dev->fsa_dev) 4961da177e4SLinus Torvalds return -ENOMEM; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds dev->maximum_num_containers = maximum_num_containers; 4993ffd6c5aSRaghava Aditya Renukunta } 5003ffd6c5aSRaghava Aditya Renukunta for (index = 0; index < dev->maximum_num_containers; index++) { 5013ffd6c5aSRaghava Aditya Renukunta dev->fsa_dev[index].devname[0] = '\0'; 5023ffd6c5aSRaghava Aditya Renukunta dev->fsa_dev[index].valid = 0; 5031da177e4SLinus Torvalds 504fe76df42SMark Haverkamp status = aac_probe_container(dev, index); 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds if (status < 0) { 5071da177e4SLinus Torvalds printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); 5081da177e4SLinus Torvalds break; 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds return status; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds static void get_container_name_callback(void *context, struct fib * fibptr) 5151da177e4SLinus Torvalds { 5161da177e4SLinus Torvalds struct aac_get_name_resp * get_name_reply; 5171da177e4SLinus Torvalds struct scsi_cmnd * scsicmd; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds scsicmd = (struct scsi_cmnd *) context; 5201da177e4SLinus Torvalds 52103d44337SMark Haverkamp if (!aac_valid_context(scsicmd, fibptr)) 52203d44337SMark Haverkamp return; 52303d44337SMark Haverkamp 5241da177e4SLinus Torvalds dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); 525125e1874SEric Sesterhenn BUG_ON(fibptr == NULL); 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr); 5281da177e4SLinus Torvalds /* Failure is irrelevant, using default value instead */ 5291da177e4SLinus Torvalds if ((le32_to_cpu(get_name_reply->status) == CT_OK) 5301da177e4SLinus Torvalds && (get_name_reply->data[0] != '\0')) { 5311da177e4SLinus Torvalds char *sp = get_name_reply->data; 532b836439fSMahesh Rajashekhara sp[sizeof(((struct aac_get_name_resp *)NULL)->data)] = '\0'; 5331da177e4SLinus Torvalds while (*sp == ' ') 5341da177e4SLinus Torvalds ++sp; 5353b2946ccSMark Haverkamp if (*sp) { 536d4345028SFUJITA Tomonori struct inquiry_data inq; 5373b2946ccSMark Haverkamp char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; 5383b2946ccSMark Haverkamp int count = sizeof(d); 5393b2946ccSMark Haverkamp char *dp = d; 5403b2946ccSMark Haverkamp do { 5411da177e4SLinus Torvalds *dp++ = (*sp) ? *sp++ : ' '; 5421da177e4SLinus Torvalds } while (--count > 0); 543d4345028SFUJITA Tomonori 544d4345028SFUJITA Tomonori scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq)); 545d4345028SFUJITA Tomonori memcpy(inq.inqd_pid, d, sizeof(d)); 546d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq)); 5471da177e4SLinus Torvalds } 5483b2946ccSMark Haverkamp } 5493b2946ccSMark Haverkamp 5501da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 5511da177e4SLinus Torvalds 552bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 5538e0c5ebdSMark Haverkamp scsicmd->scsi_done(scsicmd); 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /** 5571da177e4SLinus Torvalds * aac_get_container_name - get container name, none blocking. 5581da177e4SLinus Torvalds */ 5599e7c349cSMark Haverkamp static int aac_get_container_name(struct scsi_cmnd * scsicmd) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds int status; 5621da177e4SLinus Torvalds struct aac_get_name *dinfo; 5631da177e4SLinus Torvalds struct fib * cmd_fibcontext; 5641da177e4SLinus Torvalds struct aac_dev * dev; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds dev = (struct aac_dev *)scsicmd->device->host->hostdata; 5671da177e4SLinus Torvalds 5686bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 5691da177e4SLinus Torvalds 570bfb35aa8SMark Haverkamp aac_fib_init(cmd_fibcontext); 5711da177e4SLinus Torvalds dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext); 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds dinfo->command = cpu_to_le32(VM_ContainerConfig); 5741da177e4SLinus Torvalds dinfo->type = cpu_to_le32(CT_READ_NAME); 5759e7c349cSMark Haverkamp dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); 5761da177e4SLinus Torvalds dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data)); 5771da177e4SLinus Torvalds 578bfb35aa8SMark Haverkamp status = aac_fib_send(ContainerCommand, 5791da177e4SLinus Torvalds cmd_fibcontext, 580fb5d40d4SMahesh Rajashekhara sizeof(struct aac_get_name_resp), 5811da177e4SLinus Torvalds FsaNormal, 5821da177e4SLinus Torvalds 0, 1, 5831da177e4SLinus Torvalds (fib_callback)get_container_name_callback, 5841da177e4SLinus Torvalds (void *) scsicmd); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* 5871da177e4SLinus Torvalds * Check that the command queued to the controller 5881da177e4SLinus Torvalds */ 58977d644d4SMark Haverkamp if (status == -EINPROGRESS) { 59077d644d4SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 5911da177e4SLinus Torvalds return 0; 59277d644d4SMark Haverkamp } 5931da177e4SLinus Torvalds 594bfb35aa8SMark Haverkamp printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); 595bfb35aa8SMark Haverkamp aac_fib_complete(cmd_fibcontext); 5961da177e4SLinus Torvalds return -1; 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds 599fe76df42SMark Haverkamp static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd) 600fe76df42SMark Haverkamp { 601fe76df42SMark Haverkamp struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; 602fe76df42SMark Haverkamp 6031a655040SSalyzyn, Mark if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1)) 604fe76df42SMark Haverkamp return aac_scsi_cmd(scsicmd); 605fe76df42SMark Haverkamp 606fe76df42SMark Haverkamp scsicmd->result = DID_NO_CONNECT << 16; 607fe76df42SMark Haverkamp scsicmd->scsi_done(scsicmd); 608fe76df42SMark Haverkamp return 0; 609fe76df42SMark Haverkamp } 610fe76df42SMark Haverkamp 6111a655040SSalyzyn, Mark static void _aac_probe_container2(void * context, struct fib * fibptr) 612fe76df42SMark Haverkamp { 61303d44337SMark Haverkamp struct fsa_dev_info *fsa_dev_ptr; 614fe76df42SMark Haverkamp int (*callback)(struct scsi_cmnd *); 61503d44337SMark Haverkamp struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; 61603d44337SMark Haverkamp 61703d44337SMark Haverkamp 6181a655040SSalyzyn, Mark if (!aac_valid_context(scsicmd, fibptr)) 6191a655040SSalyzyn, Mark return; 620fe76df42SMark Haverkamp 621fe76df42SMark Haverkamp scsicmd->SCp.Status = 0; 6221a655040SSalyzyn, Mark fsa_dev_ptr = fibptr->dev->fsa_dev; 623fe76df42SMark Haverkamp if (fsa_dev_ptr) { 624fe76df42SMark Haverkamp struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr); 625fe76df42SMark Haverkamp fsa_dev_ptr += scmd_id(scsicmd); 626fe76df42SMark Haverkamp 627fe76df42SMark Haverkamp if ((le32_to_cpu(dresp->status) == ST_OK) && 628fe76df42SMark Haverkamp (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && 629fe76df42SMark Haverkamp (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { 630b836439fSMahesh Rajashekhara if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 & 631b836439fSMahesh Rajashekhara AAC_OPTION_VARIABLE_BLOCK_SIZE)) { 632b836439fSMahesh Rajashekhara dresp->mnt[0].fileinfo.bdevinfo.block_size = 0x200; 633b836439fSMahesh Rajashekhara fsa_dev_ptr->block_size = 0x200; 634b836439fSMahesh Rajashekhara } else { 635b836439fSMahesh Rajashekhara fsa_dev_ptr->block_size = 636b836439fSMahesh Rajashekhara le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size); 637b836439fSMahesh Rajashekhara } 638fe76df42SMark Haverkamp fsa_dev_ptr->valid = 1; 639655d722cSMark Salyzyn /* sense_key holds the current state of the spin-up */ 640655d722cSMark Salyzyn if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY)) 641655d722cSMark Salyzyn fsa_dev_ptr->sense_data.sense_key = NOT_READY; 642655d722cSMark Salyzyn else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY) 643655d722cSMark Salyzyn fsa_dev_ptr->sense_data.sense_key = NO_SENSE; 644fe76df42SMark Haverkamp fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); 645fe76df42SMark Haverkamp fsa_dev_ptr->size 646fe76df42SMark Haverkamp = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + 647fe76df42SMark Haverkamp (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); 648fe76df42SMark Haverkamp fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0); 649fe76df42SMark Haverkamp } 650fe76df42SMark Haverkamp if ((fsa_dev_ptr->valid & 1) == 0) 651fe76df42SMark Haverkamp fsa_dev_ptr->valid = 0; 652fe76df42SMark Haverkamp scsicmd->SCp.Status = le32_to_cpu(dresp->count); 653fe76df42SMark Haverkamp } 654fe76df42SMark Haverkamp aac_fib_complete(fibptr); 655fe76df42SMark Haverkamp aac_fib_free(fibptr); 656fe76df42SMark Haverkamp callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); 657fe76df42SMark Haverkamp scsicmd->SCp.ptr = NULL; 6581a655040SSalyzyn, Mark (*callback)(scsicmd); 6591a655040SSalyzyn, Mark return; 660fe76df42SMark Haverkamp } 661fe76df42SMark Haverkamp 6621a655040SSalyzyn, Mark static void _aac_probe_container1(void * context, struct fib * fibptr) 663fe76df42SMark Haverkamp { 664fe76df42SMark Haverkamp struct scsi_cmnd * scsicmd; 665fe76df42SMark Haverkamp struct aac_mount * dresp; 666fe76df42SMark Haverkamp struct aac_query_mount *dinfo; 667fe76df42SMark Haverkamp int status; 668fe76df42SMark Haverkamp 669fe76df42SMark Haverkamp dresp = (struct aac_mount *) fib_data(fibptr); 670b836439fSMahesh Rajashekhara if (!(fibptr->dev->supplement_adapter_info.SupportedOptions2 & 671b836439fSMahesh Rajashekhara AAC_OPTION_VARIABLE_BLOCK_SIZE)) 672fe76df42SMark Haverkamp dresp->mnt[0].capacityhigh = 0; 673fe76df42SMark Haverkamp if ((le32_to_cpu(dresp->status) != ST_OK) || 6741a655040SSalyzyn, Mark (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { 6751a655040SSalyzyn, Mark _aac_probe_container2(context, fibptr); 6761a655040SSalyzyn, Mark return; 6771a655040SSalyzyn, Mark } 678fe76df42SMark Haverkamp scsicmd = (struct scsi_cmnd *) context; 679fe76df42SMark Haverkamp 68003d44337SMark Haverkamp if (!aac_valid_context(scsicmd, fibptr)) 6811a655040SSalyzyn, Mark return; 68203d44337SMark Haverkamp 683fe76df42SMark Haverkamp aac_fib_init(fibptr); 684fe76df42SMark Haverkamp 685fe76df42SMark Haverkamp dinfo = (struct aac_query_mount *)fib_data(fibptr); 686fe76df42SMark Haverkamp 687b836439fSMahesh Rajashekhara if (fibptr->dev->supplement_adapter_info.SupportedOptions2 & 688b836439fSMahesh Rajashekhara AAC_OPTION_VARIABLE_BLOCK_SIZE) 689b836439fSMahesh Rajashekhara dinfo->command = cpu_to_le32(VM_NameServeAllBlk); 690b836439fSMahesh Rajashekhara else 691fe76df42SMark Haverkamp dinfo->command = cpu_to_le32(VM_NameServe64); 692b836439fSMahesh Rajashekhara 693fe76df42SMark Haverkamp dinfo->count = cpu_to_le32(scmd_id(scsicmd)); 694fe76df42SMark Haverkamp dinfo->type = cpu_to_le32(FT_FILESYS); 695fe76df42SMark Haverkamp 696fe76df42SMark Haverkamp status = aac_fib_send(ContainerCommand, 697fe76df42SMark Haverkamp fibptr, 698fe76df42SMark Haverkamp sizeof(struct aac_query_mount), 699fe76df42SMark Haverkamp FsaNormal, 700fe76df42SMark Haverkamp 0, 1, 7011a655040SSalyzyn, Mark _aac_probe_container2, 702fe76df42SMark Haverkamp (void *) scsicmd); 703fe76df42SMark Haverkamp /* 704fe76df42SMark Haverkamp * Check that the command queued to the controller 705fe76df42SMark Haverkamp */ 7061a655040SSalyzyn, Mark if (status == -EINPROGRESS) 707fe76df42SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 7081a655040SSalyzyn, Mark else if (status < 0) { 709fe76df42SMark Haverkamp /* Inherit results from VM_NameServe, if any */ 710fe76df42SMark Haverkamp dresp->status = cpu_to_le32(ST_OK); 7111a655040SSalyzyn, Mark _aac_probe_container2(context, fibptr); 712fe76df42SMark Haverkamp } 713fe76df42SMark Haverkamp } 714fe76df42SMark Haverkamp 715fe76df42SMark Haverkamp static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)) 716fe76df42SMark Haverkamp { 717fe76df42SMark Haverkamp struct fib * fibptr; 718fe76df42SMark Haverkamp int status = -ENOMEM; 719fe76df42SMark Haverkamp 720fe76df42SMark Haverkamp if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) { 721fe76df42SMark Haverkamp struct aac_query_mount *dinfo; 722fe76df42SMark Haverkamp 723fe76df42SMark Haverkamp aac_fib_init(fibptr); 724fe76df42SMark Haverkamp 725fe76df42SMark Haverkamp dinfo = (struct aac_query_mount *)fib_data(fibptr); 726fe76df42SMark Haverkamp 727b836439fSMahesh Rajashekhara if (fibptr->dev->supplement_adapter_info.SupportedOptions2 & 728b836439fSMahesh Rajashekhara AAC_OPTION_VARIABLE_BLOCK_SIZE) 729b836439fSMahesh Rajashekhara dinfo->command = cpu_to_le32(VM_NameServeAllBlk); 730b836439fSMahesh Rajashekhara else 731fe76df42SMark Haverkamp dinfo->command = cpu_to_le32(VM_NameServe); 732b836439fSMahesh Rajashekhara 733fe76df42SMark Haverkamp dinfo->count = cpu_to_le32(scmd_id(scsicmd)); 734fe76df42SMark Haverkamp dinfo->type = cpu_to_le32(FT_FILESYS); 735fe76df42SMark Haverkamp scsicmd->SCp.ptr = (char *)callback; 736fe76df42SMark Haverkamp 737fe76df42SMark Haverkamp status = aac_fib_send(ContainerCommand, 738fe76df42SMark Haverkamp fibptr, 739fe76df42SMark Haverkamp sizeof(struct aac_query_mount), 740fe76df42SMark Haverkamp FsaNormal, 741fe76df42SMark Haverkamp 0, 1, 7421a655040SSalyzyn, Mark _aac_probe_container1, 743fe76df42SMark Haverkamp (void *) scsicmd); 744fe76df42SMark Haverkamp /* 745fe76df42SMark Haverkamp * Check that the command queued to the controller 746fe76df42SMark Haverkamp */ 747fe76df42SMark Haverkamp if (status == -EINPROGRESS) { 748fe76df42SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 749fe76df42SMark Haverkamp return 0; 750fe76df42SMark Haverkamp } 751fe76df42SMark Haverkamp if (status < 0) { 752fe76df42SMark Haverkamp scsicmd->SCp.ptr = NULL; 753fe76df42SMark Haverkamp aac_fib_complete(fibptr); 754fe76df42SMark Haverkamp aac_fib_free(fibptr); 755fe76df42SMark Haverkamp } 756fe76df42SMark Haverkamp } 757fe76df42SMark Haverkamp if (status < 0) { 758fe76df42SMark Haverkamp struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; 759fe76df42SMark Haverkamp if (fsa_dev_ptr) { 760fe76df42SMark Haverkamp fsa_dev_ptr += scmd_id(scsicmd); 761fe76df42SMark Haverkamp if ((fsa_dev_ptr->valid & 1) == 0) { 762fe76df42SMark Haverkamp fsa_dev_ptr->valid = 0; 763fe76df42SMark Haverkamp return (*callback)(scsicmd); 764fe76df42SMark Haverkamp } 765fe76df42SMark Haverkamp } 766fe76df42SMark Haverkamp } 767fe76df42SMark Haverkamp return status; 768fe76df42SMark Haverkamp } 769fe76df42SMark Haverkamp 7701da177e4SLinus Torvalds /** 771bfb35aa8SMark Haverkamp * aac_probe_container - query a logical volume 7721da177e4SLinus Torvalds * @dev: device to query 7731da177e4SLinus Torvalds * @cid: container identifier 7741da177e4SLinus Torvalds * 7751da177e4SLinus Torvalds * Queries the controller about the given volume. The volume information 7761da177e4SLinus Torvalds * is updated in the struct fsa_dev_info structure rather than returned. 7771da177e4SLinus Torvalds */ 778fe76df42SMark Haverkamp static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) 779fe76df42SMark Haverkamp { 780fe76df42SMark Haverkamp scsicmd->device = NULL; 781fe76df42SMark Haverkamp return 0; 782fe76df42SMark Haverkamp } 7831da177e4SLinus Torvalds 784bfb35aa8SMark Haverkamp int aac_probe_container(struct aac_dev *dev, int cid) 7851da177e4SLinus Torvalds { 786fe76df42SMark Haverkamp struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); 787fe76df42SMark Haverkamp struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL); 7881da177e4SLinus Torvalds int status; 7891da177e4SLinus Torvalds 790fe76df42SMark Haverkamp if (!scsicmd || !scsidev) { 791fe76df42SMark Haverkamp kfree(scsicmd); 792fe76df42SMark Haverkamp kfree(scsidev); 79390ee3466SMark Haverkamp return -ENOMEM; 7941da177e4SLinus Torvalds } 795fe76df42SMark Haverkamp scsicmd->list.next = NULL; 7961a655040SSalyzyn, Mark scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1; 7971da177e4SLinus Torvalds 798fe76df42SMark Haverkamp scsicmd->device = scsidev; 799fe76df42SMark Haverkamp scsidev->sdev_state = 0; 800fe76df42SMark Haverkamp scsidev->id = cid; 801fe76df42SMark Haverkamp scsidev->host = dev->scsi_host_ptr; 8021da177e4SLinus Torvalds 803fe76df42SMark Haverkamp if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0) 804fe76df42SMark Haverkamp while (scsicmd->device == scsidev) 805fe76df42SMark Haverkamp schedule(); 806802ae2f0SSalyzyn, Mark kfree(scsidev); 807fe76df42SMark Haverkamp status = scsicmd->SCp.Status; 808fe76df42SMark Haverkamp kfree(scsicmd); 8091da177e4SLinus Torvalds return status; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* Local Structure to set SCSI inquiry data strings */ 8131da177e4SLinus Torvalds struct scsi_inq { 8141da177e4SLinus Torvalds char vid[8]; /* Vendor ID */ 8151da177e4SLinus Torvalds char pid[16]; /* Product ID */ 8161da177e4SLinus Torvalds char prl[4]; /* Product Revision Level */ 8171da177e4SLinus Torvalds }; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds /** 8201da177e4SLinus Torvalds * InqStrCopy - string merge 8211da177e4SLinus Torvalds * @a: string to copy from 8221da177e4SLinus Torvalds * @b: string to copy to 8231da177e4SLinus Torvalds * 8241da177e4SLinus Torvalds * Copy a String from one location to another 8251da177e4SLinus Torvalds * without copying \0 8261da177e4SLinus Torvalds */ 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds static void inqstrcpy(char *a, char *b) 8291da177e4SLinus Torvalds { 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds while (*a != (char)0) 8321da177e4SLinus Torvalds *b++ = *a++; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds static char *container_types[] = { 8361da177e4SLinus Torvalds "None", 8371da177e4SLinus Torvalds "Volume", 8381da177e4SLinus Torvalds "Mirror", 8391da177e4SLinus Torvalds "Stripe", 8401da177e4SLinus Torvalds "RAID5", 8411da177e4SLinus Torvalds "SSRW", 8421da177e4SLinus Torvalds "SSRO", 8431da177e4SLinus Torvalds "Morph", 8441da177e4SLinus Torvalds "Legacy", 8451da177e4SLinus Torvalds "RAID4", 8461da177e4SLinus Torvalds "RAID10", 8471da177e4SLinus Torvalds "RAID00", 8481da177e4SLinus Torvalds "V-MIRRORS", 8491da177e4SLinus Torvalds "PSEUDO R4", 8501da177e4SLinus Torvalds "RAID50", 85184971738SMark Haverkamp "RAID5D", 85284971738SMark Haverkamp "RAID5D0", 85384971738SMark Haverkamp "RAID1E", 85484971738SMark Haverkamp "RAID6", 85584971738SMark Haverkamp "RAID60", 8561da177e4SLinus Torvalds "Unknown" 8571da177e4SLinus Torvalds }; 8581da177e4SLinus Torvalds 85917eaaceeSSalyzyn, Mark char * get_container_type(unsigned tindex) 86017eaaceeSSalyzyn, Mark { 86117eaaceeSSalyzyn, Mark if (tindex >= ARRAY_SIZE(container_types)) 86217eaaceeSSalyzyn, Mark tindex = ARRAY_SIZE(container_types) - 1; 86317eaaceeSSalyzyn, Mark return container_types[tindex]; 86417eaaceeSSalyzyn, Mark } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds /* Function: setinqstr 8671da177e4SLinus Torvalds * 8681da177e4SLinus Torvalds * Arguments: [1] pointer to void [1] int 8691da177e4SLinus Torvalds * 8701da177e4SLinus Torvalds * Purpose: Sets SCSI inquiry data strings for vendor, product 87125985edcSLucas De Marchi * and revision level. Allows strings to be set in platform dependent 87225985edcSLucas De Marchi * files instead of in OS dependent driver source. 8731da177e4SLinus Torvalds */ 8741da177e4SLinus Torvalds 875794d0601SMark Haverkamp static void setinqstr(struct aac_dev *dev, void *data, int tindex) 8761da177e4SLinus Torvalds { 8771da177e4SLinus Torvalds struct scsi_inq *str; 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ 880794d0601SMark Haverkamp memset(str, ' ', sizeof(*str)); 881794d0601SMark Haverkamp 882794d0601SMark Haverkamp if (dev->supplement_adapter_info.AdapterTypeText[0]) { 883794d0601SMark Haverkamp char * cp = dev->supplement_adapter_info.AdapterTypeText; 8843bc8070fSSalyzyn, Mark int c; 8853bc8070fSSalyzyn, Mark if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C')) 8863bc8070fSSalyzyn, Mark inqstrcpy("SMC", str->vid); 8873bc8070fSSalyzyn, Mark else { 8883bc8070fSSalyzyn, Mark c = sizeof(str->vid); 889794d0601SMark Haverkamp while (*cp && *cp != ' ' && --c) 890794d0601SMark Haverkamp ++cp; 891794d0601SMark Haverkamp c = *cp; 892794d0601SMark Haverkamp *cp = '\0'; 893794d0601SMark Haverkamp inqstrcpy (dev->supplement_adapter_info.AdapterTypeText, 894794d0601SMark Haverkamp str->vid); 895794d0601SMark Haverkamp *cp = c; 896794d0601SMark Haverkamp while (*cp && *cp != ' ') 897794d0601SMark Haverkamp ++cp; 8983bc8070fSSalyzyn, Mark } 899794d0601SMark Haverkamp while (*cp == ' ') 900794d0601SMark Haverkamp ++cp; 901794d0601SMark Haverkamp /* last six chars reserved for vol type */ 902794d0601SMark Haverkamp c = 0; 903794d0601SMark Haverkamp if (strlen(cp) > sizeof(str->pid)) { 904794d0601SMark Haverkamp c = cp[sizeof(str->pid)]; 905794d0601SMark Haverkamp cp[sizeof(str->pid)] = '\0'; 906794d0601SMark Haverkamp } 907794d0601SMark Haverkamp inqstrcpy (cp, str->pid); 908794d0601SMark Haverkamp if (c) 909794d0601SMark Haverkamp cp[sizeof(str->pid)] = c; 910794d0601SMark Haverkamp } else { 911794d0601SMark Haverkamp struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype); 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds inqstrcpy (mp->vname, str->vid); 914794d0601SMark Haverkamp /* last six chars reserved for vol type */ 915794d0601SMark Haverkamp inqstrcpy (mp->model, str->pid); 916794d0601SMark Haverkamp } 9171da177e4SLinus Torvalds 9186391a113STobias Klauser if (tindex < ARRAY_SIZE(container_types)){ 9191da177e4SLinus Torvalds char *findit = str->pid; 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds for ( ; *findit != ' '; findit++); /* walk till we find a space */ 9221da177e4SLinus Torvalds /* RAID is superfluous in the context of a RAID device */ 9231da177e4SLinus Torvalds if (memcmp(findit-4, "RAID", 4) == 0) 9241da177e4SLinus Torvalds *(findit -= 4) = ' '; 925794d0601SMark Haverkamp if (((findit - str->pid) + strlen(container_types[tindex])) 926794d0601SMark Haverkamp < (sizeof(str->pid) + sizeof(str->prl))) 9271da177e4SLinus Torvalds inqstrcpy (container_types[tindex], findit + 1); 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds inqstrcpy ("V1.0", str->prl); 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds 93288e2f98eSSalyzyn, Mark static void get_container_serial_callback(void *context, struct fib * fibptr) 93388e2f98eSSalyzyn, Mark { 93488e2f98eSSalyzyn, Mark struct aac_get_serial_resp * get_serial_reply; 93588e2f98eSSalyzyn, Mark struct scsi_cmnd * scsicmd; 93688e2f98eSSalyzyn, Mark 93788e2f98eSSalyzyn, Mark BUG_ON(fibptr == NULL); 93888e2f98eSSalyzyn, Mark 93988e2f98eSSalyzyn, Mark scsicmd = (struct scsi_cmnd *) context; 94088e2f98eSSalyzyn, Mark if (!aac_valid_context(scsicmd, fibptr)) 94188e2f98eSSalyzyn, Mark return; 94288e2f98eSSalyzyn, Mark 94388e2f98eSSalyzyn, Mark get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr); 94488e2f98eSSalyzyn, Mark /* Failure is irrelevant, using default value instead */ 94588e2f98eSSalyzyn, Mark if (le32_to_cpu(get_serial_reply->status) == CT_OK) { 9465d910649SMahesh Rajashekhara /*Check to see if it's for VPD 0x83 or 0x80 */ 9475d910649SMahesh Rajashekhara if (scsicmd->cmnd[2] == 0x83) { 9485d910649SMahesh Rajashekhara /* vpd page 0x83 - Device Identification Page */ 9495d910649SMahesh Rajashekhara int i; 9505d910649SMahesh Rajashekhara TVPD_Page83 VPDPage83Data; 9515d910649SMahesh Rajashekhara 9525d910649SMahesh Rajashekhara memset(((u8 *)&VPDPage83Data), 0, 9535d910649SMahesh Rajashekhara sizeof(VPDPage83Data)); 9545d910649SMahesh Rajashekhara 9555d910649SMahesh Rajashekhara /* DIRECT_ACCESS_DEVIC */ 9565d910649SMahesh Rajashekhara VPDPage83Data.DeviceType = 0; 9575d910649SMahesh Rajashekhara /* DEVICE_CONNECTED */ 9585d910649SMahesh Rajashekhara VPDPage83Data.DeviceTypeQualifier = 0; 9595d910649SMahesh Rajashekhara /* VPD_DEVICE_IDENTIFIERS */ 9605d910649SMahesh Rajashekhara VPDPage83Data.PageCode = 0x83; 9615d910649SMahesh Rajashekhara VPDPage83Data.Reserved = 0; 9625d910649SMahesh Rajashekhara VPDPage83Data.PageLength = 9635d910649SMahesh Rajashekhara sizeof(VPDPage83Data.IdDescriptorType1) + 9645d910649SMahesh Rajashekhara sizeof(VPDPage83Data.IdDescriptorType2); 9655d910649SMahesh Rajashekhara 9665d910649SMahesh Rajashekhara /* T10 Vendor Identifier Field Format */ 9675d910649SMahesh Rajashekhara /* VpdCodeSetAscii */ 9685d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.CodeSet = 2; 9695d910649SMahesh Rajashekhara /* VpdIdentifierTypeVendorId */ 9705d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.IdentifierType = 1; 9715d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.IdentifierLength = 9725d910649SMahesh Rajashekhara sizeof(VPDPage83Data.IdDescriptorType1) - 4; 9735d910649SMahesh Rajashekhara 9745d910649SMahesh Rajashekhara /* "ADAPTEC " for adaptec */ 9755d910649SMahesh Rajashekhara memcpy(VPDPage83Data.IdDescriptorType1.VendId, 9765d910649SMahesh Rajashekhara "ADAPTEC ", 9775d910649SMahesh Rajashekhara sizeof(VPDPage83Data.IdDescriptorType1.VendId)); 9785d910649SMahesh Rajashekhara memcpy(VPDPage83Data.IdDescriptorType1.ProductId, 9795d910649SMahesh Rajashekhara "ARRAY ", 9805d910649SMahesh Rajashekhara sizeof( 9815d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.ProductId)); 9825d910649SMahesh Rajashekhara 9835d910649SMahesh Rajashekhara /* Convert to ascii based serial number. 9845d910649SMahesh Rajashekhara * The LSB is the the end. 9855d910649SMahesh Rajashekhara */ 9865d910649SMahesh Rajashekhara for (i = 0; i < 8; i++) { 9875d910649SMahesh Rajashekhara u8 temp = 9885d910649SMahesh Rajashekhara (u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF); 9895d910649SMahesh Rajashekhara if (temp > 0x9) { 9905d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.SerialNumber[i] = 9915d910649SMahesh Rajashekhara 'A' + (temp - 0xA); 9925d910649SMahesh Rajashekhara } else { 9935d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType1.SerialNumber[i] = 9945d910649SMahesh Rajashekhara '0' + temp; 9955d910649SMahesh Rajashekhara } 9965d910649SMahesh Rajashekhara } 9975d910649SMahesh Rajashekhara 9985d910649SMahesh Rajashekhara /* VpdCodeSetBinary */ 9995d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.CodeSet = 1; 10005d910649SMahesh Rajashekhara /* VpdIdentifierTypeEUI64 */ 10015d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.IdentifierType = 2; 10025d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.IdentifierLength = 10035d910649SMahesh Rajashekhara sizeof(VPDPage83Data.IdDescriptorType2) - 4; 10045d910649SMahesh Rajashekhara 10055d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0; 10065d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0; 10075d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0; 10085d910649SMahesh Rajashekhara 10095d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.EU64Id.Serial = 10105d910649SMahesh Rajashekhara get_serial_reply->uid; 10115d910649SMahesh Rajashekhara VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0; 10125d910649SMahesh Rajashekhara 10135d910649SMahesh Rajashekhara /* Move the inquiry data to the response buffer. */ 10145d910649SMahesh Rajashekhara scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data, 10155d910649SMahesh Rajashekhara sizeof(VPDPage83Data)); 10165d910649SMahesh Rajashekhara } else { 10175d910649SMahesh Rajashekhara /* It must be for VPD 0x80 */ 101888e2f98eSSalyzyn, Mark char sp[13]; 101988e2f98eSSalyzyn, Mark /* EVPD bit set */ 102088e2f98eSSalyzyn, Mark sp[0] = INQD_PDT_DA; 102188e2f98eSSalyzyn, Mark sp[1] = scsicmd->cmnd[2]; 102288e2f98eSSalyzyn, Mark sp[2] = 0; 102388e2f98eSSalyzyn, Mark sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", 102488e2f98eSSalyzyn, Mark le32_to_cpu(get_serial_reply->uid)); 10255d910649SMahesh Rajashekhara scsi_sg_copy_from_buffer(scsicmd, sp, 10265d910649SMahesh Rajashekhara sizeof(sp)); 10275d910649SMahesh Rajashekhara } 102888e2f98eSSalyzyn, Mark } 102988e2f98eSSalyzyn, Mark 103088e2f98eSSalyzyn, Mark scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 103188e2f98eSSalyzyn, Mark 103288e2f98eSSalyzyn, Mark aac_fib_complete(fibptr); 103388e2f98eSSalyzyn, Mark scsicmd->scsi_done(scsicmd); 103488e2f98eSSalyzyn, Mark } 103588e2f98eSSalyzyn, Mark 103688e2f98eSSalyzyn, Mark /** 103788e2f98eSSalyzyn, Mark * aac_get_container_serial - get container serial, none blocking. 103888e2f98eSSalyzyn, Mark */ 103988e2f98eSSalyzyn, Mark static int aac_get_container_serial(struct scsi_cmnd * scsicmd) 104088e2f98eSSalyzyn, Mark { 104188e2f98eSSalyzyn, Mark int status; 104288e2f98eSSalyzyn, Mark struct aac_get_serial *dinfo; 104388e2f98eSSalyzyn, Mark struct fib * cmd_fibcontext; 104488e2f98eSSalyzyn, Mark struct aac_dev * dev; 104588e2f98eSSalyzyn, Mark 104688e2f98eSSalyzyn, Mark dev = (struct aac_dev *)scsicmd->device->host->hostdata; 104788e2f98eSSalyzyn, Mark 10486bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 104988e2f98eSSalyzyn, Mark 105088e2f98eSSalyzyn, Mark aac_fib_init(cmd_fibcontext); 105188e2f98eSSalyzyn, Mark dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext); 105288e2f98eSSalyzyn, Mark 105388e2f98eSSalyzyn, Mark dinfo->command = cpu_to_le32(VM_ContainerConfig); 105488e2f98eSSalyzyn, Mark dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID); 105588e2f98eSSalyzyn, Mark dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); 105688e2f98eSSalyzyn, Mark 105788e2f98eSSalyzyn, Mark status = aac_fib_send(ContainerCommand, 105888e2f98eSSalyzyn, Mark cmd_fibcontext, 1059fb5d40d4SMahesh Rajashekhara sizeof(struct aac_get_serial_resp), 106088e2f98eSSalyzyn, Mark FsaNormal, 106188e2f98eSSalyzyn, Mark 0, 1, 106288e2f98eSSalyzyn, Mark (fib_callback) get_container_serial_callback, 106388e2f98eSSalyzyn, Mark (void *) scsicmd); 106488e2f98eSSalyzyn, Mark 106588e2f98eSSalyzyn, Mark /* 106688e2f98eSSalyzyn, Mark * Check that the command queued to the controller 106788e2f98eSSalyzyn, Mark */ 106888e2f98eSSalyzyn, Mark if (status == -EINPROGRESS) { 106988e2f98eSSalyzyn, Mark scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 107088e2f98eSSalyzyn, Mark return 0; 107188e2f98eSSalyzyn, Mark } 107288e2f98eSSalyzyn, Mark 107388e2f98eSSalyzyn, Mark printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status); 107488e2f98eSSalyzyn, Mark aac_fib_complete(cmd_fibcontext); 107588e2f98eSSalyzyn, Mark return -1; 107688e2f98eSSalyzyn, Mark } 107788e2f98eSSalyzyn, Mark 107888e2f98eSSalyzyn, Mark /* Function: setinqserial 107988e2f98eSSalyzyn, Mark * 108088e2f98eSSalyzyn, Mark * Arguments: [1] pointer to void [1] int 108188e2f98eSSalyzyn, Mark * 108288e2f98eSSalyzyn, Mark * Purpose: Sets SCSI Unit Serial number. 108388e2f98eSSalyzyn, Mark * This is a fake. We should read a proper 108488e2f98eSSalyzyn, Mark * serial number from the container. <SuSE>But 108588e2f98eSSalyzyn, Mark * without docs it's quite hard to do it :-) 108688e2f98eSSalyzyn, Mark * So this will have to do in the meantime.</SuSE> 108788e2f98eSSalyzyn, Mark */ 108888e2f98eSSalyzyn, Mark 108988e2f98eSSalyzyn, Mark static int setinqserial(struct aac_dev *dev, void *data, int cid) 109088e2f98eSSalyzyn, Mark { 109188e2f98eSSalyzyn, Mark /* 109288e2f98eSSalyzyn, Mark * This breaks array migration. 109388e2f98eSSalyzyn, Mark */ 109488e2f98eSSalyzyn, Mark return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X", 109588e2f98eSSalyzyn, Mark le32_to_cpu(dev->adapter_info.serial[0]), cid); 109688e2f98eSSalyzyn, Mark } 109788e2f98eSSalyzyn, Mark 10988e31e607SSalyzyn, Mark static inline void set_sense(struct sense_data *sense_data, u8 sense_key, 10998e31e607SSalyzyn, Mark u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) 11001da177e4SLinus Torvalds { 11018e31e607SSalyzyn, Mark u8 *sense_buf = (u8 *)sense_data; 11028e31e607SSalyzyn, Mark /* Sense data valid, err code 70h */ 11038e31e607SSalyzyn, Mark sense_buf[0] = 0x70; /* No info field */ 11041da177e4SLinus Torvalds sense_buf[1] = 0; /* Segment number, always zero */ 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds sense_buf[2] = sense_key; /* Sense key */ 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds sense_buf[12] = sense_code; /* Additional sense code */ 11091da177e4SLinus Torvalds sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ 11108e31e607SSalyzyn, Mark 11111da177e4SLinus Torvalds if (sense_key == ILLEGAL_REQUEST) { 11128e31e607SSalyzyn, Mark sense_buf[7] = 10; /* Additional sense length */ 11131da177e4SLinus Torvalds 11148e31e607SSalyzyn, Mark sense_buf[15] = bit_pointer; 11151da177e4SLinus Torvalds /* Illegal parameter is in the parameter block */ 11161da177e4SLinus Torvalds if (sense_code == SENCODE_INVALID_CDB_FIELD) 11178e31e607SSalyzyn, Mark sense_buf[15] |= 0xc0;/* Std sense key specific field */ 11181da177e4SLinus Torvalds /* Illegal parameter is in the CDB block */ 11191da177e4SLinus Torvalds sense_buf[16] = field_pointer >> 8; /* MSB */ 11201da177e4SLinus Torvalds sense_buf[17] = field_pointer; /* LSB */ 11218e31e607SSalyzyn, Mark } else 11228e31e607SSalyzyn, Mark sense_buf[7] = 6; /* Additional sense length */ 11231da177e4SLinus Torvalds } 11241da177e4SLinus Torvalds 1125e8f32de5SMark Haverkamp static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) 1126e8f32de5SMark Haverkamp { 1127e8f32de5SMark Haverkamp if (lba & 0xffffffff00000000LL) { 1128e8f32de5SMark Haverkamp int cid = scmd_id(cmd); 1129e8f32de5SMark Haverkamp dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 1130e8f32de5SMark Haverkamp cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 1131e8f32de5SMark Haverkamp SAM_STAT_CHECK_CONDITION; 11328e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 11338e31e607SSalyzyn, Mark HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 11348e31e607SSalyzyn, Mark ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 1135e8f32de5SMark Haverkamp memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 11363ace426fSSalyzyn, Mark min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 11373ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE)); 1138e8f32de5SMark Haverkamp cmd->scsi_done(cmd); 1139e8f32de5SMark Haverkamp return 1; 1140e8f32de5SMark Haverkamp } 1141e8f32de5SMark Haverkamp return 0; 1142e8f32de5SMark Haverkamp } 1143e8f32de5SMark Haverkamp 1144e8f32de5SMark Haverkamp static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) 1145e8f32de5SMark Haverkamp { 1146e8f32de5SMark Haverkamp return 0; 1147e8f32de5SMark Haverkamp } 1148e8f32de5SMark Haverkamp 1149e8f32de5SMark Haverkamp static void io_callback(void *context, struct fib * fibptr); 1150e8f32de5SMark Haverkamp 1151e8f32de5SMark Haverkamp static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 1152e8f32de5SMark Haverkamp { 115385d22bbfSMahesh Rajashekhara struct aac_dev *dev = fib->dev; 115485d22bbfSMahesh Rajashekhara u16 fibsize, command; 11550b433447SMahesh Rajashekhara long ret; 115685d22bbfSMahesh Rajashekhara 1157e8f32de5SMark Haverkamp aac_fib_init(fib); 1158d1ef4da8SRaghava Aditya Renukunta if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 1159d1ef4da8SRaghava Aditya Renukunta dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && 1160d1ef4da8SRaghava Aditya Renukunta !dev->sync_mode) { 116185d22bbfSMahesh Rajashekhara struct aac_raw_io2 *readcmd2; 116285d22bbfSMahesh Rajashekhara readcmd2 = (struct aac_raw_io2 *) fib_data(fib); 116385d22bbfSMahesh Rajashekhara memset(readcmd2, 0, sizeof(struct aac_raw_io2)); 116485d22bbfSMahesh Rajashekhara readcmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff)); 116585d22bbfSMahesh Rajashekhara readcmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 1166b836439fSMahesh Rajashekhara readcmd2->byteCount = cpu_to_le32(count * 1167b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 116885d22bbfSMahesh Rajashekhara readcmd2->cid = cpu_to_le16(scmd_id(cmd)); 116985d22bbfSMahesh Rajashekhara readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ); 11700b433447SMahesh Rajashekhara ret = aac_build_sgraw2(cmd, readcmd2, 11710b433447SMahesh Rajashekhara dev->scsi_host_ptr->sg_tablesize); 11720b433447SMahesh Rajashekhara if (ret < 0) 11730b433447SMahesh Rajashekhara return ret; 117485d22bbfSMahesh Rajashekhara command = ContainerRawIo2; 117585d22bbfSMahesh Rajashekhara fibsize = sizeof(struct aac_raw_io2) + 117685d22bbfSMahesh Rajashekhara ((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212)); 117785d22bbfSMahesh Rajashekhara } else { 117885d22bbfSMahesh Rajashekhara struct aac_raw_io *readcmd; 1179e8f32de5SMark Haverkamp readcmd = (struct aac_raw_io *) fib_data(fib); 1180e8f32de5SMark Haverkamp readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); 1181e8f32de5SMark Haverkamp readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 1182b836439fSMahesh Rajashekhara readcmd->count = cpu_to_le32(count * 1183b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 1184e8f32de5SMark Haverkamp readcmd->cid = cpu_to_le16(scmd_id(cmd)); 118585d22bbfSMahesh Rajashekhara readcmd->flags = cpu_to_le16(RIO_TYPE_READ); 1186e8f32de5SMark Haverkamp readcmd->bpTotal = 0; 1187e8f32de5SMark Haverkamp readcmd->bpComplete = 0; 11880b433447SMahesh Rajashekhara ret = aac_build_sgraw(cmd, &readcmd->sg); 11890b433447SMahesh Rajashekhara if (ret < 0) 11900b433447SMahesh Rajashekhara return ret; 119185d22bbfSMahesh Rajashekhara command = ContainerRawIo; 119285d22bbfSMahesh Rajashekhara fibsize = sizeof(struct aac_raw_io) + 119385d22bbfSMahesh Rajashekhara ((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw)); 119485d22bbfSMahesh Rajashekhara } 119585d22bbfSMahesh Rajashekhara 1196e8f32de5SMark Haverkamp BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); 1197e8f32de5SMark Haverkamp /* 1198e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1199e8f32de5SMark Haverkamp */ 120085d22bbfSMahesh Rajashekhara return aac_fib_send(command, 1201e8f32de5SMark Haverkamp fib, 1202e8f32de5SMark Haverkamp fibsize, 1203e8f32de5SMark Haverkamp FsaNormal, 1204e8f32de5SMark Haverkamp 0, 1, 1205e8f32de5SMark Haverkamp (fib_callback) io_callback, 1206e8f32de5SMark Haverkamp (void *) cmd); 1207e8f32de5SMark Haverkamp } 1208e8f32de5SMark Haverkamp 1209e8f32de5SMark Haverkamp static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 1210e8f32de5SMark Haverkamp { 1211e8f32de5SMark Haverkamp u16 fibsize; 1212e8f32de5SMark Haverkamp struct aac_read64 *readcmd; 12130b433447SMahesh Rajashekhara long ret; 12140b433447SMahesh Rajashekhara 1215e8f32de5SMark Haverkamp aac_fib_init(fib); 1216e8f32de5SMark Haverkamp readcmd = (struct aac_read64 *) fib_data(fib); 1217e8f32de5SMark Haverkamp readcmd->command = cpu_to_le32(VM_CtHostRead64); 1218e8f32de5SMark Haverkamp readcmd->cid = cpu_to_le16(scmd_id(cmd)); 1219e8f32de5SMark Haverkamp readcmd->sector_count = cpu_to_le16(count); 1220e8f32de5SMark Haverkamp readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 1221e8f32de5SMark Haverkamp readcmd->pad = 0; 1222e8f32de5SMark Haverkamp readcmd->flags = 0; 1223e8f32de5SMark Haverkamp 12240b433447SMahesh Rajashekhara ret = aac_build_sg64(cmd, &readcmd->sg); 12250b433447SMahesh Rajashekhara if (ret < 0) 12260b433447SMahesh Rajashekhara return ret; 1227e8f32de5SMark Haverkamp fibsize = sizeof(struct aac_read64) + 1228e8f32de5SMark Haverkamp ((le32_to_cpu(readcmd->sg.count) - 1) * 1229e8f32de5SMark Haverkamp sizeof (struct sgentry64)); 1230e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1231e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1232e8f32de5SMark Haverkamp /* 1233e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1234e8f32de5SMark Haverkamp */ 1235e8f32de5SMark Haverkamp return aac_fib_send(ContainerCommand64, 1236e8f32de5SMark Haverkamp fib, 1237e8f32de5SMark Haverkamp fibsize, 1238e8f32de5SMark Haverkamp FsaNormal, 1239e8f32de5SMark Haverkamp 0, 1, 1240e8f32de5SMark Haverkamp (fib_callback) io_callback, 1241e8f32de5SMark Haverkamp (void *) cmd); 1242e8f32de5SMark Haverkamp } 1243e8f32de5SMark Haverkamp 1244e8f32de5SMark Haverkamp static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 1245e8f32de5SMark Haverkamp { 1246e8f32de5SMark Haverkamp u16 fibsize; 1247e8f32de5SMark Haverkamp struct aac_read *readcmd; 1248b836439fSMahesh Rajashekhara struct aac_dev *dev = fib->dev; 12490b433447SMahesh Rajashekhara long ret; 12500b433447SMahesh Rajashekhara 1251e8f32de5SMark Haverkamp aac_fib_init(fib); 1252e8f32de5SMark Haverkamp readcmd = (struct aac_read *) fib_data(fib); 1253e8f32de5SMark Haverkamp readcmd->command = cpu_to_le32(VM_CtBlockRead); 1254f3307f72SChristoph Hellwig readcmd->cid = cpu_to_le32(scmd_id(cmd)); 1255e8f32de5SMark Haverkamp readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 1256b836439fSMahesh Rajashekhara readcmd->count = cpu_to_le32(count * 1257b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 1258e8f32de5SMark Haverkamp 12590b433447SMahesh Rajashekhara ret = aac_build_sg(cmd, &readcmd->sg); 12600b433447SMahesh Rajashekhara if (ret < 0) 12610b433447SMahesh Rajashekhara return ret; 1262e8f32de5SMark Haverkamp fibsize = sizeof(struct aac_read) + 1263e8f32de5SMark Haverkamp ((le32_to_cpu(readcmd->sg.count) - 1) * 1264e8f32de5SMark Haverkamp sizeof (struct sgentry)); 1265e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1266e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1267e8f32de5SMark Haverkamp /* 1268e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1269e8f32de5SMark Haverkamp */ 1270e8f32de5SMark Haverkamp return aac_fib_send(ContainerCommand, 1271e8f32de5SMark Haverkamp fib, 1272e8f32de5SMark Haverkamp fibsize, 1273e8f32de5SMark Haverkamp FsaNormal, 1274e8f32de5SMark Haverkamp 0, 1, 1275e8f32de5SMark Haverkamp (fib_callback) io_callback, 1276e8f32de5SMark Haverkamp (void *) cmd); 1277e8f32de5SMark Haverkamp } 1278e8f32de5SMark Haverkamp 12799d399cc7SSalyzyn, Mark static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 1280e8f32de5SMark Haverkamp { 128185d22bbfSMahesh Rajashekhara struct aac_dev *dev = fib->dev; 128285d22bbfSMahesh Rajashekhara u16 fibsize, command; 12830b433447SMahesh Rajashekhara long ret; 128485d22bbfSMahesh Rajashekhara 1285e8f32de5SMark Haverkamp aac_fib_init(fib); 1286d1ef4da8SRaghava Aditya Renukunta if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 1287d1ef4da8SRaghava Aditya Renukunta dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && 1288d1ef4da8SRaghava Aditya Renukunta !dev->sync_mode) { 128985d22bbfSMahesh Rajashekhara struct aac_raw_io2 *writecmd2; 129085d22bbfSMahesh Rajashekhara writecmd2 = (struct aac_raw_io2 *) fib_data(fib); 129185d22bbfSMahesh Rajashekhara memset(writecmd2, 0, sizeof(struct aac_raw_io2)); 129285d22bbfSMahesh Rajashekhara writecmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff)); 129385d22bbfSMahesh Rajashekhara writecmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 1294b836439fSMahesh Rajashekhara writecmd2->byteCount = cpu_to_le32(count * 1295b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 129685d22bbfSMahesh Rajashekhara writecmd2->cid = cpu_to_le16(scmd_id(cmd)); 129785d22bbfSMahesh Rajashekhara writecmd2->flags = (fua && ((aac_cache & 5) != 1) && 129885d22bbfSMahesh Rajashekhara (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? 129985d22bbfSMahesh Rajashekhara cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) : 130085d22bbfSMahesh Rajashekhara cpu_to_le16(RIO2_IO_TYPE_WRITE); 13010b433447SMahesh Rajashekhara ret = aac_build_sgraw2(cmd, writecmd2, 13020b433447SMahesh Rajashekhara dev->scsi_host_ptr->sg_tablesize); 13030b433447SMahesh Rajashekhara if (ret < 0) 13040b433447SMahesh Rajashekhara return ret; 130585d22bbfSMahesh Rajashekhara command = ContainerRawIo2; 130685d22bbfSMahesh Rajashekhara fibsize = sizeof(struct aac_raw_io2) + 130785d22bbfSMahesh Rajashekhara ((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212)); 130885d22bbfSMahesh Rajashekhara } else { 130985d22bbfSMahesh Rajashekhara struct aac_raw_io *writecmd; 1310e8f32de5SMark Haverkamp writecmd = (struct aac_raw_io *) fib_data(fib); 1311e8f32de5SMark Haverkamp writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); 1312e8f32de5SMark Haverkamp writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 1313b836439fSMahesh Rajashekhara writecmd->count = cpu_to_le32(count * 1314b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 1315e8f32de5SMark Haverkamp writecmd->cid = cpu_to_le16(scmd_id(cmd)); 131695e852e1SSalyzyn, Mark writecmd->flags = (fua && ((aac_cache & 5) != 1) && 131795e852e1SSalyzyn, Mark (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? 131885d22bbfSMahesh Rajashekhara cpu_to_le16(RIO_TYPE_WRITE|RIO_SUREWRITE) : 131985d22bbfSMahesh Rajashekhara cpu_to_le16(RIO_TYPE_WRITE); 1320e8f32de5SMark Haverkamp writecmd->bpTotal = 0; 1321e8f32de5SMark Haverkamp writecmd->bpComplete = 0; 13220b433447SMahesh Rajashekhara ret = aac_build_sgraw(cmd, &writecmd->sg); 13230b433447SMahesh Rajashekhara if (ret < 0) 13240b433447SMahesh Rajashekhara return ret; 132585d22bbfSMahesh Rajashekhara command = ContainerRawIo; 132685d22bbfSMahesh Rajashekhara fibsize = sizeof(struct aac_raw_io) + 132785d22bbfSMahesh Rajashekhara ((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw)); 132885d22bbfSMahesh Rajashekhara } 132985d22bbfSMahesh Rajashekhara 1330e8f32de5SMark Haverkamp BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); 1331e8f32de5SMark Haverkamp /* 1332e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1333e8f32de5SMark Haverkamp */ 133485d22bbfSMahesh Rajashekhara return aac_fib_send(command, 1335e8f32de5SMark Haverkamp fib, 1336e8f32de5SMark Haverkamp fibsize, 1337e8f32de5SMark Haverkamp FsaNormal, 1338e8f32de5SMark Haverkamp 0, 1, 1339e8f32de5SMark Haverkamp (fib_callback) io_callback, 1340e8f32de5SMark Haverkamp (void *) cmd); 1341e8f32de5SMark Haverkamp } 1342e8f32de5SMark Haverkamp 13439d399cc7SSalyzyn, Mark static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 1344e8f32de5SMark Haverkamp { 1345e8f32de5SMark Haverkamp u16 fibsize; 1346e8f32de5SMark Haverkamp struct aac_write64 *writecmd; 13470b433447SMahesh Rajashekhara long ret; 13480b433447SMahesh Rajashekhara 1349e8f32de5SMark Haverkamp aac_fib_init(fib); 1350e8f32de5SMark Haverkamp writecmd = (struct aac_write64 *) fib_data(fib); 1351e8f32de5SMark Haverkamp writecmd->command = cpu_to_le32(VM_CtHostWrite64); 1352e8f32de5SMark Haverkamp writecmd->cid = cpu_to_le16(scmd_id(cmd)); 1353e8f32de5SMark Haverkamp writecmd->sector_count = cpu_to_le16(count); 1354e8f32de5SMark Haverkamp writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 1355e8f32de5SMark Haverkamp writecmd->pad = 0; 1356e8f32de5SMark Haverkamp writecmd->flags = 0; 1357e8f32de5SMark Haverkamp 13580b433447SMahesh Rajashekhara ret = aac_build_sg64(cmd, &writecmd->sg); 13590b433447SMahesh Rajashekhara if (ret < 0) 13600b433447SMahesh Rajashekhara return ret; 1361e8f32de5SMark Haverkamp fibsize = sizeof(struct aac_write64) + 1362e8f32de5SMark Haverkamp ((le32_to_cpu(writecmd->sg.count) - 1) * 1363e8f32de5SMark Haverkamp sizeof (struct sgentry64)); 1364e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1365e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1366e8f32de5SMark Haverkamp /* 1367e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1368e8f32de5SMark Haverkamp */ 1369e8f32de5SMark Haverkamp return aac_fib_send(ContainerCommand64, 1370e8f32de5SMark Haverkamp fib, 1371e8f32de5SMark Haverkamp fibsize, 1372e8f32de5SMark Haverkamp FsaNormal, 1373e8f32de5SMark Haverkamp 0, 1, 1374e8f32de5SMark Haverkamp (fib_callback) io_callback, 1375e8f32de5SMark Haverkamp (void *) cmd); 1376e8f32de5SMark Haverkamp } 1377e8f32de5SMark Haverkamp 13789d399cc7SSalyzyn, Mark static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 1379e8f32de5SMark Haverkamp { 1380e8f32de5SMark Haverkamp u16 fibsize; 1381e8f32de5SMark Haverkamp struct aac_write *writecmd; 1382b836439fSMahesh Rajashekhara struct aac_dev *dev = fib->dev; 13830b433447SMahesh Rajashekhara long ret; 13840b433447SMahesh Rajashekhara 1385e8f32de5SMark Haverkamp aac_fib_init(fib); 1386e8f32de5SMark Haverkamp writecmd = (struct aac_write *) fib_data(fib); 1387e8f32de5SMark Haverkamp writecmd->command = cpu_to_le32(VM_CtBlockWrite); 1388f3307f72SChristoph Hellwig writecmd->cid = cpu_to_le32(scmd_id(cmd)); 1389e8f32de5SMark Haverkamp writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 1390b836439fSMahesh Rajashekhara writecmd->count = cpu_to_le32(count * 1391b836439fSMahesh Rajashekhara dev->fsa_dev[scmd_id(cmd)].block_size); 1392e8f32de5SMark Haverkamp writecmd->sg.count = cpu_to_le32(1); 1393e8f32de5SMark Haverkamp /* ->stable is not used - it did mean which type of write */ 1394e8f32de5SMark Haverkamp 13950b433447SMahesh Rajashekhara ret = aac_build_sg(cmd, &writecmd->sg); 13960b433447SMahesh Rajashekhara if (ret < 0) 13970b433447SMahesh Rajashekhara return ret; 1398e8f32de5SMark Haverkamp fibsize = sizeof(struct aac_write) + 1399e8f32de5SMark Haverkamp ((le32_to_cpu(writecmd->sg.count) - 1) * 1400e8f32de5SMark Haverkamp sizeof (struct sgentry)); 1401e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1402e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1403e8f32de5SMark Haverkamp /* 1404e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1405e8f32de5SMark Haverkamp */ 1406e8f32de5SMark Haverkamp return aac_fib_send(ContainerCommand, 1407e8f32de5SMark Haverkamp fib, 1408e8f32de5SMark Haverkamp fibsize, 1409e8f32de5SMark Haverkamp FsaNormal, 1410e8f32de5SMark Haverkamp 0, 1, 1411e8f32de5SMark Haverkamp (fib_callback) io_callback, 1412e8f32de5SMark Haverkamp (void *) cmd); 1413e8f32de5SMark Haverkamp } 1414e8f32de5SMark Haverkamp 1415e8f32de5SMark Haverkamp static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd) 1416e8f32de5SMark Haverkamp { 1417e8f32de5SMark Haverkamp struct aac_srb * srbcmd; 1418e8f32de5SMark Haverkamp u32 flag; 1419e8f32de5SMark Haverkamp u32 timeout; 1420e8f32de5SMark Haverkamp 1421e8f32de5SMark Haverkamp aac_fib_init(fib); 1422e8f32de5SMark Haverkamp switch(cmd->sc_data_direction){ 1423e8f32de5SMark Haverkamp case DMA_TO_DEVICE: 1424e8f32de5SMark Haverkamp flag = SRB_DataOut; 1425e8f32de5SMark Haverkamp break; 1426e8f32de5SMark Haverkamp case DMA_BIDIRECTIONAL: 1427e8f32de5SMark Haverkamp flag = SRB_DataIn | SRB_DataOut; 1428e8f32de5SMark Haverkamp break; 1429e8f32de5SMark Haverkamp case DMA_FROM_DEVICE: 1430e8f32de5SMark Haverkamp flag = SRB_DataIn; 1431e8f32de5SMark Haverkamp break; 1432e8f32de5SMark Haverkamp case DMA_NONE: 1433e8f32de5SMark Haverkamp default: /* shuts up some versions of gcc */ 1434e8f32de5SMark Haverkamp flag = SRB_NoDataXfer; 1435e8f32de5SMark Haverkamp break; 1436e8f32de5SMark Haverkamp } 1437e8f32de5SMark Haverkamp 1438e8f32de5SMark Haverkamp srbcmd = (struct aac_srb*) fib_data(fib); 1439e8f32de5SMark Haverkamp srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); 1440e8f32de5SMark Haverkamp srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd))); 1441e8f32de5SMark Haverkamp srbcmd->id = cpu_to_le32(scmd_id(cmd)); 1442e8f32de5SMark Haverkamp srbcmd->lun = cpu_to_le32(cmd->device->lun); 1443e8f32de5SMark Haverkamp srbcmd->flags = cpu_to_le32(flag); 1444242f9dcbSJens Axboe timeout = cmd->request->timeout/HZ; 1445e8f32de5SMark Haverkamp if (timeout == 0) 1446e8f32de5SMark Haverkamp timeout = 1; 1447e8f32de5SMark Haverkamp srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds 1448e8f32de5SMark Haverkamp srbcmd->retry_limit = 0; /* Obsolete parameter */ 1449e8f32de5SMark Haverkamp srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len); 1450e8f32de5SMark Haverkamp return srbcmd; 1451e8f32de5SMark Haverkamp } 1452e8f32de5SMark Haverkamp 1453ab5d129fSRaghava Aditya Renukunta static struct aac_hba_cmd_req *aac_construct_hbacmd(struct fib *fib, 1454ab5d129fSRaghava Aditya Renukunta struct scsi_cmnd *cmd) 1455ab5d129fSRaghava Aditya Renukunta { 1456ab5d129fSRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd; 1457ab5d129fSRaghava Aditya Renukunta struct aac_dev *dev; 1458ab5d129fSRaghava Aditya Renukunta int bus, target; 1459ab5d129fSRaghava Aditya Renukunta u64 address; 1460ab5d129fSRaghava Aditya Renukunta 1461ab5d129fSRaghava Aditya Renukunta dev = (struct aac_dev *)cmd->device->host->hostdata; 1462ab5d129fSRaghava Aditya Renukunta 1463ab5d129fSRaghava Aditya Renukunta hbacmd = (struct aac_hba_cmd_req *)fib->hw_fib_va; 1464ab5d129fSRaghava Aditya Renukunta memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 1465ab5d129fSRaghava Aditya Renukunta /* iu_type is a parameter of aac_hba_send */ 1466ab5d129fSRaghava Aditya Renukunta switch (cmd->sc_data_direction) { 1467ab5d129fSRaghava Aditya Renukunta case DMA_TO_DEVICE: 1468ab5d129fSRaghava Aditya Renukunta hbacmd->byte1 = 2; 1469ab5d129fSRaghava Aditya Renukunta break; 1470ab5d129fSRaghava Aditya Renukunta case DMA_FROM_DEVICE: 1471ab5d129fSRaghava Aditya Renukunta case DMA_BIDIRECTIONAL: 1472ab5d129fSRaghava Aditya Renukunta hbacmd->byte1 = 1; 1473ab5d129fSRaghava Aditya Renukunta break; 1474ab5d129fSRaghava Aditya Renukunta case DMA_NONE: 1475ab5d129fSRaghava Aditya Renukunta default: 1476ab5d129fSRaghava Aditya Renukunta break; 1477ab5d129fSRaghava Aditya Renukunta } 1478ab5d129fSRaghava Aditya Renukunta hbacmd->lun[1] = cpu_to_le32(cmd->device->lun); 1479ab5d129fSRaghava Aditya Renukunta 1480ab5d129fSRaghava Aditya Renukunta bus = aac_logical_to_phys(scmd_channel(cmd)); 1481ab5d129fSRaghava Aditya Renukunta target = scmd_id(cmd); 1482ab5d129fSRaghava Aditya Renukunta hbacmd->it_nexus = dev->hba_map[bus][target].rmw_nexus; 1483ab5d129fSRaghava Aditya Renukunta 1484ab5d129fSRaghava Aditya Renukunta /* we fill in reply_qid later in aac_src_deliver_message */ 1485ab5d129fSRaghava Aditya Renukunta /* we fill in iu_type, request_id later in aac_hba_send */ 1486ab5d129fSRaghava Aditya Renukunta /* we fill in emb_data_desc_count later in aac_build_sghba */ 1487ab5d129fSRaghava Aditya Renukunta 1488ab5d129fSRaghava Aditya Renukunta memcpy(hbacmd->cdb, cmd->cmnd, cmd->cmd_len); 1489ab5d129fSRaghava Aditya Renukunta hbacmd->data_length = cpu_to_le32(scsi_bufflen(cmd)); 1490ab5d129fSRaghava Aditya Renukunta 1491ab5d129fSRaghava Aditya Renukunta address = (u64)fib->hw_error_pa; 1492ab5d129fSRaghava Aditya Renukunta hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 1493ab5d129fSRaghava Aditya Renukunta hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 1494ab5d129fSRaghava Aditya Renukunta hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 1495ab5d129fSRaghava Aditya Renukunta 1496ab5d129fSRaghava Aditya Renukunta return hbacmd; 1497ab5d129fSRaghava Aditya Renukunta } 1498ab5d129fSRaghava Aditya Renukunta 1499e8f32de5SMark Haverkamp static void aac_srb_callback(void *context, struct fib * fibptr); 1500e8f32de5SMark Haverkamp 1501e8f32de5SMark Haverkamp static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) 1502e8f32de5SMark Haverkamp { 1503e8f32de5SMark Haverkamp u16 fibsize; 1504e8f32de5SMark Haverkamp struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); 15050b433447SMahesh Rajashekhara long ret; 1506e8f32de5SMark Haverkamp 15070b433447SMahesh Rajashekhara ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg); 15080b433447SMahesh Rajashekhara if (ret < 0) 15090b433447SMahesh Rajashekhara return ret; 1510727eead6SFUJITA Tomonori srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); 1511e8f32de5SMark Haverkamp 1512e8f32de5SMark Haverkamp memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 1513e8f32de5SMark Haverkamp memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); 1514e8f32de5SMark Haverkamp /* 1515e8f32de5SMark Haverkamp * Build Scatter/Gather list 1516e8f32de5SMark Haverkamp */ 1517e8f32de5SMark Haverkamp fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + 1518e8f32de5SMark Haverkamp ((le32_to_cpu(srbcmd->sg.count) & 0xff) * 1519e8f32de5SMark Haverkamp sizeof (struct sgentry64)); 1520e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1521e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1522e8f32de5SMark Haverkamp 1523e8f32de5SMark Haverkamp /* 1524e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1525e8f32de5SMark Haverkamp */ 1526e8f32de5SMark Haverkamp return aac_fib_send(ScsiPortCommand64, fib, 1527e8f32de5SMark Haverkamp fibsize, FsaNormal, 0, 1, 1528e8f32de5SMark Haverkamp (fib_callback) aac_srb_callback, 1529e8f32de5SMark Haverkamp (void *) cmd); 1530e8f32de5SMark Haverkamp } 1531e8f32de5SMark Haverkamp 1532e8f32de5SMark Haverkamp static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) 1533e8f32de5SMark Haverkamp { 1534e8f32de5SMark Haverkamp u16 fibsize; 1535e8f32de5SMark Haverkamp struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); 15360b433447SMahesh Rajashekhara long ret; 1537e8f32de5SMark Haverkamp 15380b433447SMahesh Rajashekhara ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg); 15390b433447SMahesh Rajashekhara if (ret < 0) 15400b433447SMahesh Rajashekhara return ret; 1541727eead6SFUJITA Tomonori srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); 1542e8f32de5SMark Haverkamp 1543e8f32de5SMark Haverkamp memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 1544e8f32de5SMark Haverkamp memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); 1545e8f32de5SMark Haverkamp /* 1546e8f32de5SMark Haverkamp * Build Scatter/Gather list 1547e8f32de5SMark Haverkamp */ 1548e8f32de5SMark Haverkamp fibsize = sizeof (struct aac_srb) + 1549e8f32de5SMark Haverkamp (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 1550e8f32de5SMark Haverkamp sizeof (struct sgentry)); 1551e8f32de5SMark Haverkamp BUG_ON (fibsize > (fib->dev->max_fib_size - 1552e8f32de5SMark Haverkamp sizeof(struct aac_fibhdr))); 1553e8f32de5SMark Haverkamp 1554e8f32de5SMark Haverkamp /* 1555e8f32de5SMark Haverkamp * Now send the Fib to the adapter 1556e8f32de5SMark Haverkamp */ 1557e8f32de5SMark Haverkamp return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1, 1558e8f32de5SMark Haverkamp (fib_callback) aac_srb_callback, (void *) cmd); 1559e8f32de5SMark Haverkamp } 1560e8f32de5SMark Haverkamp 156194cf6ba1SSalyzyn, Mark static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) 156294cf6ba1SSalyzyn, Mark { 1563d8e96507SLeubner, Achim if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac && 156494cf6ba1SSalyzyn, Mark (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) 156594cf6ba1SSalyzyn, Mark return FAILED; 156694cf6ba1SSalyzyn, Mark return aac_scsi_32(fib, cmd); 156794cf6ba1SSalyzyn, Mark } 156894cf6ba1SSalyzyn, Mark 1569ab5d129fSRaghava Aditya Renukunta static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd) 1570ab5d129fSRaghava Aditya Renukunta { 1571ab5d129fSRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd); 1572ab5d129fSRaghava Aditya Renukunta struct aac_dev *dev; 1573ab5d129fSRaghava Aditya Renukunta long ret; 1574ab5d129fSRaghava Aditya Renukunta 1575ab5d129fSRaghava Aditya Renukunta dev = (struct aac_dev *)cmd->device->host->hostdata; 1576ab5d129fSRaghava Aditya Renukunta 1577ab5d129fSRaghava Aditya Renukunta ret = aac_build_sghba(cmd, hbacmd, 1578ab5d129fSRaghava Aditya Renukunta dev->scsi_host_ptr->sg_tablesize, (u64)fib->hw_sgl_pa); 1579ab5d129fSRaghava Aditya Renukunta if (ret < 0) 1580ab5d129fSRaghava Aditya Renukunta return ret; 1581ab5d129fSRaghava Aditya Renukunta 1582ab5d129fSRaghava Aditya Renukunta /* 1583ab5d129fSRaghava Aditya Renukunta * Now send the HBA command to the adapter 1584ab5d129fSRaghava Aditya Renukunta */ 1585ab5d129fSRaghava Aditya Renukunta fib->hbacmd_size = 64 + le32_to_cpu(hbacmd->emb_data_desc_count) * 1586ab5d129fSRaghava Aditya Renukunta sizeof(struct aac_hba_sgl); 1587ab5d129fSRaghava Aditya Renukunta 1588ab5d129fSRaghava Aditya Renukunta return aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, fib, 1589ab5d129fSRaghava Aditya Renukunta (fib_callback) aac_hba_callback, 1590ab5d129fSRaghava Aditya Renukunta (void *) cmd); 1591ab5d129fSRaghava Aditya Renukunta } 1592ab5d129fSRaghava Aditya Renukunta 159371a91ca4SRaghava Aditya Renukunta int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target) 159471a91ca4SRaghava Aditya Renukunta { 159571a91ca4SRaghava Aditya Renukunta struct fib *fibptr; 159671a91ca4SRaghava Aditya Renukunta struct aac_srb *srbcmd; 159771a91ca4SRaghava Aditya Renukunta struct sgmap64 *sg64; 159871a91ca4SRaghava Aditya Renukunta struct aac_ciss_identify_pd *identify_resp; 159971a91ca4SRaghava Aditya Renukunta dma_addr_t addr; 160071a91ca4SRaghava Aditya Renukunta u32 vbus, vid; 160171a91ca4SRaghava Aditya Renukunta u16 fibsize, datasize; 160271a91ca4SRaghava Aditya Renukunta int rcode = -ENOMEM; 160371a91ca4SRaghava Aditya Renukunta 1604ab5d129fSRaghava Aditya Renukunta 160571a91ca4SRaghava Aditya Renukunta fibptr = aac_fib_alloc(dev); 160671a91ca4SRaghava Aditya Renukunta if (!fibptr) 160771a91ca4SRaghava Aditya Renukunta goto out; 160871a91ca4SRaghava Aditya Renukunta 160971a91ca4SRaghava Aditya Renukunta fibsize = sizeof(struct aac_srb) - 161071a91ca4SRaghava Aditya Renukunta sizeof(struct sgentry) + sizeof(struct sgentry64); 161171a91ca4SRaghava Aditya Renukunta datasize = sizeof(struct aac_ciss_identify_pd); 161271a91ca4SRaghava Aditya Renukunta 161371a91ca4SRaghava Aditya Renukunta identify_resp = pci_alloc_consistent(dev->pdev, datasize, &addr); 161471a91ca4SRaghava Aditya Renukunta 161571a91ca4SRaghava Aditya Renukunta if (!identify_resp) 161671a91ca4SRaghava Aditya Renukunta goto fib_free_ptr; 161771a91ca4SRaghava Aditya Renukunta 161871a91ca4SRaghava Aditya Renukunta vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus); 161971a91ca4SRaghava Aditya Renukunta vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget); 162071a91ca4SRaghava Aditya Renukunta 162171a91ca4SRaghava Aditya Renukunta aac_fib_init(fibptr); 162271a91ca4SRaghava Aditya Renukunta 162371a91ca4SRaghava Aditya Renukunta srbcmd = (struct aac_srb *) fib_data(fibptr); 162471a91ca4SRaghava Aditya Renukunta srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); 162571a91ca4SRaghava Aditya Renukunta srbcmd->channel = cpu_to_le32(vbus); 162671a91ca4SRaghava Aditya Renukunta srbcmd->id = cpu_to_le32(vid); 162771a91ca4SRaghava Aditya Renukunta srbcmd->lun = 0; 162871a91ca4SRaghava Aditya Renukunta srbcmd->flags = cpu_to_le32(SRB_DataIn); 162971a91ca4SRaghava Aditya Renukunta srbcmd->timeout = cpu_to_le32(10); 163071a91ca4SRaghava Aditya Renukunta srbcmd->retry_limit = 0; 163171a91ca4SRaghava Aditya Renukunta srbcmd->cdb_size = cpu_to_le32(12); 163271a91ca4SRaghava Aditya Renukunta srbcmd->count = cpu_to_le32(datasize); 163371a91ca4SRaghava Aditya Renukunta 163471a91ca4SRaghava Aditya Renukunta memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 163571a91ca4SRaghava Aditya Renukunta srbcmd->cdb[0] = 0x26; 163671a91ca4SRaghava Aditya Renukunta srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF); 163771a91ca4SRaghava Aditya Renukunta srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE; 163871a91ca4SRaghava Aditya Renukunta 163971a91ca4SRaghava Aditya Renukunta sg64 = (struct sgmap64 *)&srbcmd->sg; 164071a91ca4SRaghava Aditya Renukunta sg64->count = cpu_to_le32(1); 164171a91ca4SRaghava Aditya Renukunta sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16)); 164271a91ca4SRaghava Aditya Renukunta sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); 164371a91ca4SRaghava Aditya Renukunta sg64->sg[0].count = cpu_to_le32(datasize); 164471a91ca4SRaghava Aditya Renukunta 164571a91ca4SRaghava Aditya Renukunta rcode = aac_fib_send(ScsiPortCommand64, 164671a91ca4SRaghava Aditya Renukunta fibptr, fibsize, FsaNormal, 1, 1, NULL, NULL); 164771a91ca4SRaghava Aditya Renukunta 164871a91ca4SRaghava Aditya Renukunta if (identify_resp->current_queue_depth_limit <= 0 || 164971a91ca4SRaghava Aditya Renukunta identify_resp->current_queue_depth_limit > 32) 165071a91ca4SRaghava Aditya Renukunta dev->hba_map[bus][target].qd_limit = 32; 165171a91ca4SRaghava Aditya Renukunta else 165271a91ca4SRaghava Aditya Renukunta dev->hba_map[bus][target].qd_limit = 165371a91ca4SRaghava Aditya Renukunta identify_resp->current_queue_depth_limit; 165471a91ca4SRaghava Aditya Renukunta 165571a91ca4SRaghava Aditya Renukunta pci_free_consistent(dev->pdev, datasize, (void *)identify_resp, addr); 165671a91ca4SRaghava Aditya Renukunta 165771a91ca4SRaghava Aditya Renukunta aac_fib_complete(fibptr); 165871a91ca4SRaghava Aditya Renukunta 165971a91ca4SRaghava Aditya Renukunta fib_free_ptr: 166071a91ca4SRaghava Aditya Renukunta aac_fib_free(fibptr); 166171a91ca4SRaghava Aditya Renukunta out: 166271a91ca4SRaghava Aditya Renukunta return rcode; 166371a91ca4SRaghava Aditya Renukunta } 166471a91ca4SRaghava Aditya Renukunta 1665c83b11e3SRaghava Aditya Renukunta /** 1666c83b11e3SRaghava Aditya Renukunta * aac_update hba_map()- update current hba map with data from FW 1667c83b11e3SRaghava Aditya Renukunta * @dev: aac_dev structure 1668c83b11e3SRaghava Aditya Renukunta * @phys_luns: FW information from report phys luns 1669c83b11e3SRaghava Aditya Renukunta * 1670c83b11e3SRaghava Aditya Renukunta * Update our hba map with the information gathered from the FW 1671c83b11e3SRaghava Aditya Renukunta */ 1672c83b11e3SRaghava Aditya Renukunta void aac_update_hba_map(struct aac_dev *dev, 16736223a39fSRaghava Aditya Renukunta struct aac_ciss_phys_luns_resp *phys_luns, int rescan) 1674c83b11e3SRaghava Aditya Renukunta { 1675c83b11e3SRaghava Aditya Renukunta /* ok and extended reporting */ 1676c83b11e3SRaghava Aditya Renukunta u32 lun_count, nexus; 1677c83b11e3SRaghava Aditya Renukunta u32 i, bus, target; 1678c83b11e3SRaghava Aditya Renukunta u8 expose_flag, attribs; 1679c83b11e3SRaghava Aditya Renukunta u8 devtype; 1680c83b11e3SRaghava Aditya Renukunta 1681c83b11e3SRaghava Aditya Renukunta lun_count = ((phys_luns->list_length[0] << 24) 1682c83b11e3SRaghava Aditya Renukunta + (phys_luns->list_length[1] << 16) 1683c83b11e3SRaghava Aditya Renukunta + (phys_luns->list_length[2] << 8) 1684c83b11e3SRaghava Aditya Renukunta + (phys_luns->list_length[3])) / 24; 1685c83b11e3SRaghava Aditya Renukunta 1686c83b11e3SRaghava Aditya Renukunta for (i = 0; i < lun_count; ++i) { 1687c83b11e3SRaghava Aditya Renukunta 1688c83b11e3SRaghava Aditya Renukunta bus = phys_luns->lun[i].level2[1] & 0x3f; 1689c83b11e3SRaghava Aditya Renukunta target = phys_luns->lun[i].level2[0]; 1690c83b11e3SRaghava Aditya Renukunta expose_flag = phys_luns->lun[i].bus >> 6; 1691c83b11e3SRaghava Aditya Renukunta attribs = phys_luns->lun[i].node_ident[9]; 1692c83b11e3SRaghava Aditya Renukunta nexus = *((u32 *) &phys_luns->lun[i].node_ident[12]); 1693c83b11e3SRaghava Aditya Renukunta 1694c83b11e3SRaghava Aditya Renukunta if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS) 1695c83b11e3SRaghava Aditya Renukunta continue; 1696c83b11e3SRaghava Aditya Renukunta 1697c83b11e3SRaghava Aditya Renukunta dev->hba_map[bus][target].expose = expose_flag; 1698c83b11e3SRaghava Aditya Renukunta 1699c83b11e3SRaghava Aditya Renukunta if (expose_flag != 0) { 1700c83b11e3SRaghava Aditya Renukunta devtype = AAC_DEVTYPE_RAID_MEMBER; 1701c83b11e3SRaghava Aditya Renukunta goto update_devtype; 1702c83b11e3SRaghava Aditya Renukunta } 1703c83b11e3SRaghava Aditya Renukunta 1704c83b11e3SRaghava Aditya Renukunta if (nexus != 0 && (attribs & 8)) { 1705c83b11e3SRaghava Aditya Renukunta devtype = AAC_DEVTYPE_NATIVE_RAW; 1706c83b11e3SRaghava Aditya Renukunta dev->hba_map[bus][target].rmw_nexus = 1707c83b11e3SRaghava Aditya Renukunta nexus; 1708c83b11e3SRaghava Aditya Renukunta } else 1709c83b11e3SRaghava Aditya Renukunta devtype = AAC_DEVTYPE_ARC_RAW; 1710c83b11e3SRaghava Aditya Renukunta 1711c83b11e3SRaghava Aditya Renukunta if (devtype != AAC_DEVTYPE_NATIVE_RAW) 1712c83b11e3SRaghava Aditya Renukunta goto update_devtype; 1713c83b11e3SRaghava Aditya Renukunta 171471a91ca4SRaghava Aditya Renukunta if (aac_issue_bmic_identify(dev, bus, target) < 0) 171571a91ca4SRaghava Aditya Renukunta dev->hba_map[bus][target].qd_limit = 32; 171671a91ca4SRaghava Aditya Renukunta 1717c83b11e3SRaghava Aditya Renukunta update_devtype: 17186223a39fSRaghava Aditya Renukunta if (rescan == AAC_INIT) 1719c83b11e3SRaghava Aditya Renukunta dev->hba_map[bus][target].devtype = devtype; 17206223a39fSRaghava Aditya Renukunta else 17216223a39fSRaghava Aditya Renukunta dev->hba_map[bus][target].new_devtype = devtype; 1722c83b11e3SRaghava Aditya Renukunta } 1723c83b11e3SRaghava Aditya Renukunta } 1724c83b11e3SRaghava Aditya Renukunta 1725c83b11e3SRaghava Aditya Renukunta /** 1726c83b11e3SRaghava Aditya Renukunta * aac_report_phys_luns() Process topology change 1727c83b11e3SRaghava Aditya Renukunta * @dev: aac_dev structure 1728c83b11e3SRaghava Aditya Renukunta * @fibptr: fib pointer 1729c83b11e3SRaghava Aditya Renukunta * 1730c83b11e3SRaghava Aditya Renukunta * Execute a CISS REPORT PHYS LUNS and process the results into 1731c83b11e3SRaghava Aditya Renukunta * the current hba_map. 1732c83b11e3SRaghava Aditya Renukunta */ 17336223a39fSRaghava Aditya Renukunta int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan) 1734c83b11e3SRaghava Aditya Renukunta { 1735c83b11e3SRaghava Aditya Renukunta int fibsize, datasize; 1736c83b11e3SRaghava Aditya Renukunta struct aac_ciss_phys_luns_resp *phys_luns; 1737c83b11e3SRaghava Aditya Renukunta struct aac_srb *srbcmd; 1738c83b11e3SRaghava Aditya Renukunta struct sgmap64 *sg64; 1739c83b11e3SRaghava Aditya Renukunta dma_addr_t addr; 1740c83b11e3SRaghava Aditya Renukunta u32 vbus, vid; 1741c83b11e3SRaghava Aditya Renukunta u32 rcode = 0; 1742c83b11e3SRaghava Aditya Renukunta 1743c83b11e3SRaghava Aditya Renukunta /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */ 1744c83b11e3SRaghava Aditya Renukunta fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) 1745c83b11e3SRaghava Aditya Renukunta + sizeof(struct sgentry64); 1746c83b11e3SRaghava Aditya Renukunta datasize = sizeof(struct aac_ciss_phys_luns_resp) 1747c83b11e3SRaghava Aditya Renukunta + (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); 1748c83b11e3SRaghava Aditya Renukunta 1749c83b11e3SRaghava Aditya Renukunta phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent( 1750c83b11e3SRaghava Aditya Renukunta dev->pdev, datasize, &addr); 1751c83b11e3SRaghava Aditya Renukunta 1752c83b11e3SRaghava Aditya Renukunta if (phys_luns == NULL) { 1753c83b11e3SRaghava Aditya Renukunta rcode = -ENOMEM; 1754c83b11e3SRaghava Aditya Renukunta goto err_out; 1755c83b11e3SRaghava Aditya Renukunta } 1756c83b11e3SRaghava Aditya Renukunta 1757c83b11e3SRaghava Aditya Renukunta vbus = (u32) le16_to_cpu( 1758c83b11e3SRaghava Aditya Renukunta dev->supplement_adapter_info.VirtDeviceBus); 1759c83b11e3SRaghava Aditya Renukunta vid = (u32) le16_to_cpu( 1760c83b11e3SRaghava Aditya Renukunta dev->supplement_adapter_info.VirtDeviceTarget); 1761c83b11e3SRaghava Aditya Renukunta 1762c83b11e3SRaghava Aditya Renukunta aac_fib_init(fibptr); 1763c83b11e3SRaghava Aditya Renukunta 1764c83b11e3SRaghava Aditya Renukunta srbcmd = (struct aac_srb *) fib_data(fibptr); 1765c83b11e3SRaghava Aditya Renukunta srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); 1766c83b11e3SRaghava Aditya Renukunta srbcmd->channel = cpu_to_le32(vbus); 1767c83b11e3SRaghava Aditya Renukunta srbcmd->id = cpu_to_le32(vid); 1768c83b11e3SRaghava Aditya Renukunta srbcmd->lun = 0; 1769c83b11e3SRaghava Aditya Renukunta srbcmd->flags = cpu_to_le32(SRB_DataIn); 1770c83b11e3SRaghava Aditya Renukunta srbcmd->timeout = cpu_to_le32(10); 1771c83b11e3SRaghava Aditya Renukunta srbcmd->retry_limit = 0; 1772c83b11e3SRaghava Aditya Renukunta srbcmd->cdb_size = cpu_to_le32(12); 1773c83b11e3SRaghava Aditya Renukunta srbcmd->count = cpu_to_le32(datasize); 1774c83b11e3SRaghava Aditya Renukunta 1775c83b11e3SRaghava Aditya Renukunta memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 1776c83b11e3SRaghava Aditya Renukunta srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS; 1777c83b11e3SRaghava Aditya Renukunta srbcmd->cdb[1] = 2; /* extended reporting */ 1778c83b11e3SRaghava Aditya Renukunta srbcmd->cdb[8] = (u8)(datasize >> 8); 1779c83b11e3SRaghava Aditya Renukunta srbcmd->cdb[9] = (u8)(datasize); 1780c83b11e3SRaghava Aditya Renukunta 1781c83b11e3SRaghava Aditya Renukunta sg64 = (struct sgmap64 *) &srbcmd->sg; 1782c83b11e3SRaghava Aditya Renukunta sg64->count = cpu_to_le32(1); 1783c83b11e3SRaghava Aditya Renukunta sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr)); 1784c83b11e3SRaghava Aditya Renukunta sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr)); 1785c83b11e3SRaghava Aditya Renukunta sg64->sg[0].count = cpu_to_le32(datasize); 1786c83b11e3SRaghava Aditya Renukunta 1787c83b11e3SRaghava Aditya Renukunta rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize, 1788c83b11e3SRaghava Aditya Renukunta FsaNormal, 1, 1, NULL, NULL); 1789c83b11e3SRaghava Aditya Renukunta 1790c83b11e3SRaghava Aditya Renukunta /* analyse data */ 1791c83b11e3SRaghava Aditya Renukunta if (rcode >= 0 && phys_luns->resp_flag == 2) { 1792c83b11e3SRaghava Aditya Renukunta /* ok and extended reporting */ 17936223a39fSRaghava Aditya Renukunta aac_update_hba_map(dev, phys_luns, rescan); 1794c83b11e3SRaghava Aditya Renukunta } 1795c83b11e3SRaghava Aditya Renukunta 1796c83b11e3SRaghava Aditya Renukunta pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr); 1797c83b11e3SRaghava Aditya Renukunta err_out: 1798c83b11e3SRaghava Aditya Renukunta return rcode; 1799c83b11e3SRaghava Aditya Renukunta } 1800c83b11e3SRaghava Aditya Renukunta 18011da177e4SLinus Torvalds int aac_get_adapter_info(struct aac_dev* dev) 18021da177e4SLinus Torvalds { 18031da177e4SLinus Torvalds struct fib* fibptr; 18041da177e4SLinus Torvalds int rcode; 1805c83b11e3SRaghava Aditya Renukunta u32 tmp, bus, target; 18067c00ffa3SMark Haverkamp struct aac_adapter_info *info; 180784971738SMark Haverkamp struct aac_bus_info *command; 180884971738SMark Haverkamp struct aac_bus_info_response *bus_info; 18097c00ffa3SMark Haverkamp 1810bfb35aa8SMark Haverkamp if (!(fibptr = aac_fib_alloc(dev))) 18111da177e4SLinus Torvalds return -ENOMEM; 18121da177e4SLinus Torvalds 1813bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 18141da177e4SLinus Torvalds info = (struct aac_adapter_info *) fib_data(fibptr); 18157c00ffa3SMark Haverkamp memset(info,0,sizeof(*info)); 18161da177e4SLinus Torvalds 1817bfb35aa8SMark Haverkamp rcode = aac_fib_send(RequestAdapterInfo, 18181da177e4SLinus Torvalds fibptr, 18197c00ffa3SMark Haverkamp sizeof(*info), 18201da177e4SLinus Torvalds FsaNormal, 18219203344cSMark Haverkamp -1, 1, /* First `interrupt' command uses special wait */ 18221da177e4SLinus Torvalds NULL, 18231da177e4SLinus Torvalds NULL); 18241da177e4SLinus Torvalds 18257c00ffa3SMark Haverkamp if (rcode < 0) { 1826cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* FIB should be freed only after 1827cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech * getting the response from the F/W */ 1828cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode != -ERESTARTSYS) { 1829bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 1830bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 1831cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech } 18327c00ffa3SMark Haverkamp return rcode; 18337c00ffa3SMark Haverkamp } 18347c00ffa3SMark Haverkamp memcpy(&dev->adapter_info, info, sizeof(*info)); 18357c00ffa3SMark Haverkamp 1836c83b11e3SRaghava Aditya Renukunta dev->supplement_adapter_info.VirtDeviceBus = 0xffff; 18377c00ffa3SMark Haverkamp if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) { 183806a43d17SSalyzyn, Mark struct aac_supplement_adapter_info * sinfo; 18397c00ffa3SMark Haverkamp 1840bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 18417c00ffa3SMark Haverkamp 184206a43d17SSalyzyn, Mark sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr); 18437c00ffa3SMark Haverkamp 184406a43d17SSalyzyn, Mark memset(sinfo,0,sizeof(*sinfo)); 18457c00ffa3SMark Haverkamp 1846bfb35aa8SMark Haverkamp rcode = aac_fib_send(RequestSupplementAdapterInfo, 18477c00ffa3SMark Haverkamp fibptr, 184806a43d17SSalyzyn, Mark sizeof(*sinfo), 18497c00ffa3SMark Haverkamp FsaNormal, 18507c00ffa3SMark Haverkamp 1, 1, 18517c00ffa3SMark Haverkamp NULL, 18527c00ffa3SMark Haverkamp NULL); 18537c00ffa3SMark Haverkamp 18547c00ffa3SMark Haverkamp if (rcode >= 0) 185506a43d17SSalyzyn, Mark memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo)); 1856cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode == -ERESTARTSYS) { 1857cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech fibptr = aac_fib_alloc(dev); 1858cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (!fibptr) 1859cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech return -ENOMEM; 1860cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech } 1861cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech 18627c00ffa3SMark Haverkamp } 18631da177e4SLinus Torvalds 1864c83b11e3SRaghava Aditya Renukunta /* reset all previous mapped devices (i.e. for init. after IOP_RESET) */ 1865c83b11e3SRaghava Aditya Renukunta for (bus = 0; bus < AAC_MAX_BUSES; bus++) { 186671a91ca4SRaghava Aditya Renukunta for (target = 0; target < AAC_MAX_TARGETS; target++) { 1867c83b11e3SRaghava Aditya Renukunta dev->hba_map[bus][target].devtype = 0; 186871a91ca4SRaghava Aditya Renukunta dev->hba_map[bus][target].qd_limit = 0; 186971a91ca4SRaghava Aditya Renukunta } 1870c83b11e3SRaghava Aditya Renukunta } 187184971738SMark Haverkamp 187284971738SMark Haverkamp /* 187384971738SMark Haverkamp * GetBusInfo 187484971738SMark Haverkamp */ 187584971738SMark Haverkamp 1876bfb35aa8SMark Haverkamp aac_fib_init(fibptr); 187784971738SMark Haverkamp 187884971738SMark Haverkamp bus_info = (struct aac_bus_info_response *) fib_data(fibptr); 187984971738SMark Haverkamp 188084971738SMark Haverkamp memset(bus_info, 0, sizeof(*bus_info)); 188184971738SMark Haverkamp 188284971738SMark Haverkamp command = (struct aac_bus_info *)bus_info; 188384971738SMark Haverkamp 188484971738SMark Haverkamp command->Command = cpu_to_le32(VM_Ioctl); 188584971738SMark Haverkamp command->ObjType = cpu_to_le32(FT_DRIVE); 188684971738SMark Haverkamp command->MethodId = cpu_to_le32(1); 188784971738SMark Haverkamp command->CtlCmd = cpu_to_le32(GetBusInfo); 188884971738SMark Haverkamp 1889bfb35aa8SMark Haverkamp rcode = aac_fib_send(ContainerCommand, 189084971738SMark Haverkamp fibptr, 189184971738SMark Haverkamp sizeof (*bus_info), 189284971738SMark Haverkamp FsaNormal, 189384971738SMark Haverkamp 1, 1, 189484971738SMark Haverkamp NULL, NULL); 189584971738SMark Haverkamp 189694cf6ba1SSalyzyn, Mark /* reasoned default */ 189794cf6ba1SSalyzyn, Mark dev->maximum_num_physicals = 16; 189884971738SMark Haverkamp if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) { 189984971738SMark Haverkamp dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus); 190084971738SMark Haverkamp dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); 190184971738SMark Haverkamp } 190284971738SMark Haverkamp 1903c83b11e3SRaghava Aditya Renukunta if (!dev->sync_mode && dev->sa_firmware && 1904c83b11e3SRaghava Aditya Renukunta dev->supplement_adapter_info.VirtDeviceBus != 0xffff) { 1905c83b11e3SRaghava Aditya Renukunta /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */ 19066223a39fSRaghava Aditya Renukunta rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT); 1907c83b11e3SRaghava Aditya Renukunta } 1908c83b11e3SRaghava Aditya Renukunta 19098c867b25SMark Haverkamp if (!dev->in_reset) { 191024f02e1dSSalyzyn, Mark char buffer[16]; 19111da177e4SLinus Torvalds tmp = le32_to_cpu(dev->adapter_info.kernelrev); 19127c00ffa3SMark Haverkamp printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n", 19131da177e4SLinus Torvalds dev->name, 19141da177e4SLinus Torvalds dev->id, 19151da177e4SLinus Torvalds tmp>>24, 19161da177e4SLinus Torvalds (tmp>>16)&0xff, 19171da177e4SLinus Torvalds tmp&0xff, 19187c00ffa3SMark Haverkamp le32_to_cpu(dev->adapter_info.kernelbuild), 19197c00ffa3SMark Haverkamp (int)sizeof(dev->supplement_adapter_info.BuildDate), 19207c00ffa3SMark Haverkamp dev->supplement_adapter_info.BuildDate); 19211da177e4SLinus Torvalds tmp = le32_to_cpu(dev->adapter_info.monitorrev); 19221da177e4SLinus Torvalds printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n", 19231da177e4SLinus Torvalds dev->name, dev->id, 19241da177e4SLinus Torvalds tmp>>24,(tmp>>16)&0xff,tmp&0xff, 19251da177e4SLinus Torvalds le32_to_cpu(dev->adapter_info.monitorbuild)); 19261da177e4SLinus Torvalds tmp = le32_to_cpu(dev->adapter_info.biosrev); 19271da177e4SLinus Torvalds printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n", 19281da177e4SLinus Torvalds dev->name, dev->id, 19291da177e4SLinus Torvalds tmp>>24,(tmp>>16)&0xff,tmp&0xff, 19301da177e4SLinus Torvalds le32_to_cpu(dev->adapter_info.biosbuild)); 193124f02e1dSSalyzyn, Mark buffer[0] = '\0'; 1932ee959b00STony Jones if (aac_get_serial_number( 193324f02e1dSSalyzyn, Mark shost_to_class(dev->scsi_host_ptr), buffer)) 193424f02e1dSSalyzyn, Mark printk(KERN_INFO "%s%d: serial %s", 193524f02e1dSSalyzyn, Mark dev->name, dev->id, buffer); 1936a45c863fSSalyzyn, Mark if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) { 1937a45c863fSSalyzyn, Mark printk(KERN_INFO "%s%d: TSID %.*s\n", 1938a45c863fSSalyzyn, Mark dev->name, dev->id, 1939a45c863fSSalyzyn, Mark (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), 1940a45c863fSSalyzyn, Mark dev->supplement_adapter_info.VpdInfo.Tsid); 1941a45c863fSSalyzyn, Mark } 19422f7ecc55SSalyzyn, Mark if (!aac_check_reset || ((aac_check_reset == 1) && 194329c97684SSalyzyn, Mark (dev->supplement_adapter_info.SupportedOptions2 & 1944a3940da5SSalyzyn, Mark AAC_OPTION_IGNORE_RESET))) { 194529c97684SSalyzyn, Mark printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", 194629c97684SSalyzyn, Mark dev->name, dev->id); 194729c97684SSalyzyn, Mark } 19488c867b25SMark Haverkamp } 19491da177e4SLinus Torvalds 195095e852e1SSalyzyn, Mark dev->cache_protected = 0; 1951cb1042f2SSalyzyn, Mark dev->jbod = ((dev->supplement_adapter_info.FeatureBits & 1952cb1042f2SSalyzyn, Mark AAC_FEATURE_JBOD) != 0); 19531da177e4SLinus Torvalds dev->nondasd_support = 0; 19541da177e4SLinus Torvalds dev->raid_scsi_mode = 0; 195595e852e1SSalyzyn, Mark if(dev->adapter_info.options & AAC_OPT_NONDASD) 19561da177e4SLinus Torvalds dev->nondasd_support = 1; 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds /* 19591da177e4SLinus Torvalds * If the firmware supports ROMB RAID/SCSI mode and we are currently 19601da177e4SLinus Torvalds * in RAID/SCSI mode, set the flag. For now if in this mode we will 19611da177e4SLinus Torvalds * force nondasd support on. If we decide to allow the non-dasd flag 19621da177e4SLinus Torvalds * additional changes changes will have to be made to support 19631da177e4SLinus Torvalds * RAID/SCSI. the function aac_scsi_cmd in this module will have to be 19641da177e4SLinus Torvalds * changed to support the new dev->raid_scsi_mode flag instead of 19651da177e4SLinus Torvalds * leaching off of the dev->nondasd_support flag. Also in linit.c the 19661da177e4SLinus Torvalds * function aac_detect will have to be modified where it sets up the 19671da177e4SLinus Torvalds * max number of channels based on the aac->nondasd_support flag only. 19681da177e4SLinus Torvalds */ 19691da177e4SLinus Torvalds if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) && 19701da177e4SLinus Torvalds (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) { 19711da177e4SLinus Torvalds dev->nondasd_support = 1; 19721da177e4SLinus Torvalds dev->raid_scsi_mode = 1; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds if (dev->raid_scsi_mode != 0) 19751da177e4SLinus Torvalds printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n", 19761da177e4SLinus Torvalds dev->name, dev->id); 19771da177e4SLinus Torvalds 197895e852e1SSalyzyn, Mark if (nondasd != -1) 19791da177e4SLinus Torvalds dev->nondasd_support = (nondasd!=0); 19802f7ecc55SSalyzyn, Mark if (dev->nondasd_support && !dev->in_reset) 19811da177e4SLinus Torvalds printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); 19821da177e4SLinus Torvalds 1983e930438cSYang Hongyang if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32)) 1984d8e96507SLeubner, Achim dev->needs_dac = 1; 19851da177e4SLinus Torvalds dev->dac_support = 0; 1986d8e96507SLeubner, Achim if ((sizeof(dma_addr_t) > 4) && dev->needs_dac && 1987d8e96507SLeubner, Achim (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) { 19882f7ecc55SSalyzyn, Mark if (!dev->in_reset) 19892f7ecc55SSalyzyn, Mark printk(KERN_INFO "%s%d: 64bit support enabled.\n", 19902f7ecc55SSalyzyn, Mark dev->name, dev->id); 19911da177e4SLinus Torvalds dev->dac_support = 1; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds if(dacmode != -1) { 19951da177e4SLinus Torvalds dev->dac_support = (dacmode!=0); 19961da177e4SLinus Torvalds } 1997d8e96507SLeubner, Achim 1998d8e96507SLeubner, Achim /* avoid problems with AAC_QUIRK_SCSI_32 controllers */ 1999d8e96507SLeubner, Achim if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks 2000d8e96507SLeubner, Achim & AAC_QUIRK_SCSI_32)) { 2001d8e96507SLeubner, Achim dev->nondasd_support = 0; 2002d8e96507SLeubner, Achim dev->jbod = 0; 2003d8e96507SLeubner, Achim expose_physicals = 0; 2004d8e96507SLeubner, Achim } 2005d8e96507SLeubner, Achim 20061da177e4SLinus Torvalds if(dev->dac_support != 0) { 20076a35528aSYang Hongyang if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) && 20086a35528aSYang Hongyang !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) { 20092f7ecc55SSalyzyn, Mark if (!dev->in_reset) 20101da177e4SLinus Torvalds printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", 20111da177e4SLinus Torvalds dev->name, dev->id); 2012284901a9SYang Hongyang } else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) && 2013284901a9SYang Hongyang !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) { 20141da177e4SLinus Torvalds printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n", 20151da177e4SLinus Torvalds dev->name, dev->id); 20161da177e4SLinus Torvalds dev->dac_support = 0; 20171da177e4SLinus Torvalds } else { 20181da177e4SLinus Torvalds printk(KERN_WARNING"%s%d: No suitable DMA available.\n", 20191da177e4SLinus Torvalds dev->name, dev->id); 20201da177e4SLinus Torvalds rcode = -ENOMEM; 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds } 20237c00ffa3SMark Haverkamp /* 2024e8f32de5SMark Haverkamp * Deal with configuring for the individualized limits of each packet 2025e8f32de5SMark Haverkamp * interface. 20267c00ffa3SMark Haverkamp */ 2027e8f32de5SMark Haverkamp dev->a_ops.adapter_scsi = (dev->dac_support) 202894cf6ba1SSalyzyn, Mark ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32) 202994cf6ba1SSalyzyn, Mark ? aac_scsi_32_64 203094cf6ba1SSalyzyn, Mark : aac_scsi_64) 2031e8f32de5SMark Haverkamp : aac_scsi_32; 2032e8f32de5SMark Haverkamp if (dev->raw_io_interface) { 2033e8f32de5SMark Haverkamp dev->a_ops.adapter_bounds = (dev->raw_io_64) 2034e8f32de5SMark Haverkamp ? aac_bounds_64 2035e8f32de5SMark Haverkamp : aac_bounds_32; 2036e8f32de5SMark Haverkamp dev->a_ops.adapter_read = aac_read_raw_io; 2037e8f32de5SMark Haverkamp dev->a_ops.adapter_write = aac_write_raw_io; 2038e8f32de5SMark Haverkamp } else { 2039e8f32de5SMark Haverkamp dev->a_ops.adapter_bounds = aac_bounds_32; 20407c00ffa3SMark Haverkamp dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - 20417c00ffa3SMark Haverkamp sizeof(struct aac_fibhdr) - 204263a70eeaSMark Haverkamp sizeof(struct aac_write) + sizeof(struct sgentry)) / 204363a70eeaSMark Haverkamp sizeof(struct sgentry); 20447c00ffa3SMark Haverkamp if (dev->dac_support) { 2045e8f32de5SMark Haverkamp dev->a_ops.adapter_read = aac_read_block64; 2046e8f32de5SMark Haverkamp dev->a_ops.adapter_write = aac_write_block64; 20477c00ffa3SMark Haverkamp /* 20487c00ffa3SMark Haverkamp * 38 scatter gather elements 20497c00ffa3SMark Haverkamp */ 20507c00ffa3SMark Haverkamp dev->scsi_host_ptr->sg_tablesize = 20517c00ffa3SMark Haverkamp (dev->max_fib_size - 20527c00ffa3SMark Haverkamp sizeof(struct aac_fibhdr) - 20537c00ffa3SMark Haverkamp sizeof(struct aac_write64) + 205463a70eeaSMark Haverkamp sizeof(struct sgentry64)) / 205563a70eeaSMark Haverkamp sizeof(struct sgentry64); 2056e8f32de5SMark Haverkamp } else { 2057e8f32de5SMark Haverkamp dev->a_ops.adapter_read = aac_read_block; 2058e8f32de5SMark Haverkamp dev->a_ops.adapter_write = aac_write_block; 20597c00ffa3SMark Haverkamp } 20607c00ffa3SMark Haverkamp dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; 20617c00ffa3SMark Haverkamp if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { 20627c00ffa3SMark Haverkamp /* 20637c00ffa3SMark Haverkamp * Worst case size that could cause sg overflow when 20647c00ffa3SMark Haverkamp * we break up SG elements that are larger than 64KB. 20657c00ffa3SMark Haverkamp * Would be nice if we could tell the SCSI layer what 20667c00ffa3SMark Haverkamp * the maximum SG element size can be. Worst case is 20677c00ffa3SMark Haverkamp * (sg_tablesize-1) 4KB elements with one 64KB 20687c00ffa3SMark Haverkamp * element. 20697c00ffa3SMark Haverkamp * 32bit -> 468 or 238KB 64bit -> 424 or 212KB 20707c00ffa3SMark Haverkamp */ 20717c00ffa3SMark Haverkamp dev->scsi_host_ptr->max_sectors = 20727c00ffa3SMark Haverkamp (dev->scsi_host_ptr->sg_tablesize * 8) + 112; 20737c00ffa3SMark Haverkamp } 20740e68c003SMark Haverkamp } 2075ab5d129fSRaghava Aditya Renukunta if (!dev->sync_mode && dev->sa_firmware && 2076ab5d129fSRaghava Aditya Renukunta dev->scsi_host_ptr->sg_tablesize > HBA_MAX_SG_SEPARATE) 2077ab5d129fSRaghava Aditya Renukunta dev->scsi_host_ptr->sg_tablesize = dev->sg_tablesize = 2078ab5d129fSRaghava Aditya Renukunta HBA_MAX_SG_SEPARATE; 2079ab5d129fSRaghava Aditya Renukunta 2080cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech /* FIB should be freed only after getting the response from the F/W */ 2081cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech if (rcode != -ERESTARTSYS) { 2082bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 2083bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 2084cacb6dc3SPenchala Narasimha Reddy Chilakala, ERS-HCLTech } 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds return rcode; 20871da177e4SLinus Torvalds } 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds 2090e53cb35aSMark Haverkamp static void io_callback(void *context, struct fib * fibptr) 20911da177e4SLinus Torvalds { 20921da177e4SLinus Torvalds struct aac_dev *dev; 20931da177e4SLinus Torvalds struct aac_read_reply *readreply; 20941da177e4SLinus Torvalds struct scsi_cmnd *scsicmd; 20951da177e4SLinus Torvalds u32 cid; 20961da177e4SLinus Torvalds 20971da177e4SLinus Torvalds scsicmd = (struct scsi_cmnd *) context; 20981da177e4SLinus Torvalds 209903d44337SMark Haverkamp if (!aac_valid_context(scsicmd, fibptr)) 210003d44337SMark Haverkamp return; 210103d44337SMark Haverkamp 21021a655040SSalyzyn, Mark dev = fibptr->dev; 2103e5718774SMark Haverkamp cid = scmd_id(scsicmd); 21041da177e4SLinus Torvalds 21057a8cf29dSMark Haverkamp if (nblank(dprintk(x))) { 21067a8cf29dSMark Haverkamp u64 lba; 21077a8cf29dSMark Haverkamp switch (scsicmd->cmnd[0]) { 21087a8cf29dSMark Haverkamp case WRITE_6: 21097a8cf29dSMark Haverkamp case READ_6: 21107a8cf29dSMark Haverkamp lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 21117a8cf29dSMark Haverkamp (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 21127a8cf29dSMark Haverkamp break; 21137a8cf29dSMark Haverkamp case WRITE_16: 21147a8cf29dSMark Haverkamp case READ_16: 21157a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 56) | 21167a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[3] << 48) | 21177a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[4] << 40) | 21187a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[5] << 32) | 21197a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[6] << 24) | 21207a8cf29dSMark Haverkamp (scsicmd->cmnd[7] << 16) | 21217a8cf29dSMark Haverkamp (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 21227a8cf29dSMark Haverkamp break; 21237a8cf29dSMark Haverkamp case WRITE_12: 21247a8cf29dSMark Haverkamp case READ_12: 21257a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | 21267a8cf29dSMark Haverkamp (scsicmd->cmnd[3] << 16) | 21277a8cf29dSMark Haverkamp (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 21287a8cf29dSMark Haverkamp break; 21297a8cf29dSMark Haverkamp default: 21307a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | 21317a8cf29dSMark Haverkamp (scsicmd->cmnd[3] << 16) | 21327a8cf29dSMark Haverkamp (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 21337a8cf29dSMark Haverkamp break; 21347a8cf29dSMark Haverkamp } 21357a8cf29dSMark Haverkamp printk(KERN_DEBUG 21367a8cf29dSMark Haverkamp "io_callback[cpu %d]: lba = %llu, t = %ld.\n", 21377a8cf29dSMark Haverkamp smp_processor_id(), (unsigned long long)lba, jiffies); 21387a8cf29dSMark Haverkamp } 21391da177e4SLinus Torvalds 2140125e1874SEric Sesterhenn BUG_ON(fibptr == NULL); 21411da177e4SLinus Torvalds 2142727eead6SFUJITA Tomonori scsi_dma_unmap(scsicmd); 2143727eead6SFUJITA Tomonori 21441da177e4SLinus Torvalds readreply = (struct aac_read_reply *)fib_data(fibptr); 2145655d722cSMark Salyzyn switch (le32_to_cpu(readreply->status)) { 2146655d722cSMark Salyzyn case ST_OK: 2147655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2148655d722cSMark Salyzyn SAM_STAT_GOOD; 2149655d722cSMark Salyzyn dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE; 2150655d722cSMark Salyzyn break; 2151655d722cSMark Salyzyn case ST_NOT_READY: 2152655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2153655d722cSMark Salyzyn SAM_STAT_CHECK_CONDITION; 2154655d722cSMark Salyzyn set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY, 2155655d722cSMark Salyzyn SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0); 2156655d722cSMark Salyzyn memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 2157655d722cSMark Salyzyn min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 2158655d722cSMark Salyzyn SCSI_SENSE_BUFFERSIZE)); 2159655d722cSMark Salyzyn break; 2160f956a669SRaghava Aditya Renukunta case ST_MEDERR: 2161f956a669SRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2162f956a669SRaghava Aditya Renukunta SAM_STAT_CHECK_CONDITION; 2163f956a669SRaghava Aditya Renukunta set_sense(&dev->fsa_dev[cid].sense_data, MEDIUM_ERROR, 2164f956a669SRaghava Aditya Renukunta SENCODE_UNRECOVERED_READ_ERROR, ASENCODE_NO_SENSE, 0, 0); 2165f956a669SRaghava Aditya Renukunta memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 2166f956a669SRaghava Aditya Renukunta min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 2167f956a669SRaghava Aditya Renukunta SCSI_SENSE_BUFFERSIZE)); 2168f956a669SRaghava Aditya Renukunta break; 2169655d722cSMark Salyzyn default: 21707c00ffa3SMark Haverkamp #ifdef AAC_DETAILED_STATUS_INFO 2171e53cb35aSMark Haverkamp printk(KERN_WARNING "io_callback: io failed, status = %d\n", 21721da177e4SLinus Torvalds le32_to_cpu(readreply->status)); 21737c00ffa3SMark Haverkamp #endif 2174655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2175655d722cSMark Salyzyn SAM_STAT_CHECK_CONDITION; 21768e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 21778e31e607SSalyzyn, Mark HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 21788e31e607SSalyzyn, Mark ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 21791da177e4SLinus Torvalds memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 21803ace426fSSalyzyn, Mark min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 21813ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE)); 2182655d722cSMark Salyzyn break; 21831da177e4SLinus Torvalds } 2184bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 21851da177e4SLinus Torvalds 21868e0c5ebdSMark Haverkamp scsicmd->scsi_done(scsicmd); 21871da177e4SLinus Torvalds } 21881da177e4SLinus Torvalds 21899e7c349cSMark Haverkamp static int aac_read(struct scsi_cmnd * scsicmd) 21901da177e4SLinus Torvalds { 21917a8cf29dSMark Haverkamp u64 lba; 21921da177e4SLinus Torvalds u32 count; 21931da177e4SLinus Torvalds int status; 21941da177e4SLinus Torvalds struct aac_dev *dev; 21951da177e4SLinus Torvalds struct fib * cmd_fibcontext; 2196da3cc679SRajashekhara, Mahesh int cid; 21971da177e4SLinus Torvalds 21981da177e4SLinus Torvalds dev = (struct aac_dev *)scsicmd->device->host->hostdata; 21991da177e4SLinus Torvalds /* 22001da177e4SLinus Torvalds * Get block address and transfer length 22011da177e4SLinus Torvalds */ 22027a8cf29dSMark Haverkamp switch (scsicmd->cmnd[0]) { 22037a8cf29dSMark Haverkamp case READ_6: 22049e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd))); 22051da177e4SLinus Torvalds 22067a8cf29dSMark Haverkamp lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 22077a8cf29dSMark Haverkamp (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 22081da177e4SLinus Torvalds count = scsicmd->cmnd[4]; 22091da177e4SLinus Torvalds 22101da177e4SLinus Torvalds if (count == 0) 22111da177e4SLinus Torvalds count = 256; 22127a8cf29dSMark Haverkamp break; 22137a8cf29dSMark Haverkamp case READ_16: 22149e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd))); 22157a8cf29dSMark Haverkamp 22167a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 56) | 22177a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[3] << 48) | 22187a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[4] << 40) | 22197a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[5] << 32) | 22207a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[6] << 24) | 22217a8cf29dSMark Haverkamp (scsicmd->cmnd[7] << 16) | 22227a8cf29dSMark Haverkamp (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 22237a8cf29dSMark Haverkamp count = (scsicmd->cmnd[10] << 24) | 22247a8cf29dSMark Haverkamp (scsicmd->cmnd[11] << 16) | 22257a8cf29dSMark Haverkamp (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; 22267a8cf29dSMark Haverkamp break; 22277a8cf29dSMark Haverkamp case READ_12: 22289e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd))); 22297a8cf29dSMark Haverkamp 22307a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | 22317a8cf29dSMark Haverkamp (scsicmd->cmnd[3] << 16) | 22327a8cf29dSMark Haverkamp (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 22337a8cf29dSMark Haverkamp count = (scsicmd->cmnd[6] << 24) | 22347a8cf29dSMark Haverkamp (scsicmd->cmnd[7] << 16) | 22357a8cf29dSMark Haverkamp (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 22367a8cf29dSMark Haverkamp break; 22377a8cf29dSMark Haverkamp default: 22389e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd))); 22391da177e4SLinus Torvalds 22407a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | 22417a8cf29dSMark Haverkamp (scsicmd->cmnd[3] << 16) | 22427a8cf29dSMark Haverkamp (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 22431da177e4SLinus Torvalds count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; 22447a8cf29dSMark Haverkamp break; 22451da177e4SLinus Torvalds } 2246da3cc679SRajashekhara, Mahesh 2247da3cc679SRajashekhara, Mahesh if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { 2248da3cc679SRajashekhara, Mahesh cid = scmd_id(scsicmd); 2249da3cc679SRajashekhara, Mahesh dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 2250da3cc679SRajashekhara, Mahesh scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2251da3cc679SRajashekhara, Mahesh SAM_STAT_CHECK_CONDITION; 2252da3cc679SRajashekhara, Mahesh set_sense(&dev->fsa_dev[cid].sense_data, 2253da3cc679SRajashekhara, Mahesh HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 2254da3cc679SRajashekhara, Mahesh ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 2255da3cc679SRajashekhara, Mahesh memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 2256da3cc679SRajashekhara, Mahesh min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 2257da3cc679SRajashekhara, Mahesh SCSI_SENSE_BUFFERSIZE)); 2258da3cc679SRajashekhara, Mahesh scsicmd->scsi_done(scsicmd); 2259da3cc679SRajashekhara, Mahesh return 1; 2260da3cc679SRajashekhara, Mahesh } 2261da3cc679SRajashekhara, Mahesh 22627a8cf29dSMark Haverkamp dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", 22637c00ffa3SMark Haverkamp smp_processor_id(), (unsigned long long)lba, jiffies)); 2264e8f32de5SMark Haverkamp if (aac_adapter_bounds(dev,scsicmd,lba)) 22657a8cf29dSMark Haverkamp return 0; 22661da177e4SLinus Torvalds /* 22671da177e4SLinus Torvalds * Alocate and initialize a Fib 22681da177e4SLinus Torvalds */ 22696bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 22701da177e4SLinus Torvalds 2271e8f32de5SMark Haverkamp status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count); 22721da177e4SLinus Torvalds 22731da177e4SLinus Torvalds /* 22741da177e4SLinus Torvalds * Check that the command queued to the controller 22751da177e4SLinus Torvalds */ 227677d644d4SMark Haverkamp if (status == -EINPROGRESS) { 227777d644d4SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 22781da177e4SLinus Torvalds return 0; 227977d644d4SMark Haverkamp } 22801da177e4SLinus Torvalds 2281bfb35aa8SMark Haverkamp printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); 22821da177e4SLinus Torvalds /* 22831da177e4SLinus Torvalds * For some reason, the Fib didn't queue, return QUEUE_FULL 22841da177e4SLinus Torvalds */ 22851da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; 22868e0c5ebdSMark Haverkamp scsicmd->scsi_done(scsicmd); 2287bfb35aa8SMark Haverkamp aac_fib_complete(cmd_fibcontext); 2288bfb35aa8SMark Haverkamp aac_fib_free(cmd_fibcontext); 22891da177e4SLinus Torvalds return 0; 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 22929e7c349cSMark Haverkamp static int aac_write(struct scsi_cmnd * scsicmd) 22931da177e4SLinus Torvalds { 22947a8cf29dSMark Haverkamp u64 lba; 22951da177e4SLinus Torvalds u32 count; 22969d399cc7SSalyzyn, Mark int fua; 22971da177e4SLinus Torvalds int status; 22981da177e4SLinus Torvalds struct aac_dev *dev; 22991da177e4SLinus Torvalds struct fib * cmd_fibcontext; 2300da3cc679SRajashekhara, Mahesh int cid; 23011da177e4SLinus Torvalds 23021da177e4SLinus Torvalds dev = (struct aac_dev *)scsicmd->device->host->hostdata; 23031da177e4SLinus Torvalds /* 23041da177e4SLinus Torvalds * Get block address and transfer length 23051da177e4SLinus Torvalds */ 23061da177e4SLinus Torvalds if (scsicmd->cmnd[0] == WRITE_6) /* 6 byte command */ 23071da177e4SLinus Torvalds { 23081da177e4SLinus Torvalds lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 23091da177e4SLinus Torvalds count = scsicmd->cmnd[4]; 23101da177e4SLinus Torvalds if (count == 0) 23111da177e4SLinus Torvalds count = 256; 23129d399cc7SSalyzyn, Mark fua = 0; 23137a8cf29dSMark Haverkamp } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */ 23149e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd))); 23157a8cf29dSMark Haverkamp 23167a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 56) | 23177a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[3] << 48) | 23187a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[4] << 40) | 23197a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[5] << 32) | 23207a8cf29dSMark Haverkamp ((u64)scsicmd->cmnd[6] << 24) | 23217a8cf29dSMark Haverkamp (scsicmd->cmnd[7] << 16) | 23227a8cf29dSMark Haverkamp (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 23237a8cf29dSMark Haverkamp count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | 23247a8cf29dSMark Haverkamp (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; 23259d399cc7SSalyzyn, Mark fua = scsicmd->cmnd[1] & 0x8; 23267a8cf29dSMark Haverkamp } else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */ 23279e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd))); 23287a8cf29dSMark Haverkamp 23297a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) 23307a8cf29dSMark Haverkamp | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 23317a8cf29dSMark Haverkamp count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) 23327a8cf29dSMark Haverkamp | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 23339d399cc7SSalyzyn, Mark fua = scsicmd->cmnd[1] & 0x8; 23341da177e4SLinus Torvalds } else { 23359e7c349cSMark Haverkamp dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd))); 23367a8cf29dSMark Haverkamp lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 23371da177e4SLinus Torvalds count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; 23389d399cc7SSalyzyn, Mark fua = scsicmd->cmnd[1] & 0x8; 23391da177e4SLinus Torvalds } 2340da3cc679SRajashekhara, Mahesh 2341da3cc679SRajashekhara, Mahesh if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { 2342da3cc679SRajashekhara, Mahesh cid = scmd_id(scsicmd); 2343da3cc679SRajashekhara, Mahesh dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 2344da3cc679SRajashekhara, Mahesh scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2345da3cc679SRajashekhara, Mahesh SAM_STAT_CHECK_CONDITION; 2346da3cc679SRajashekhara, Mahesh set_sense(&dev->fsa_dev[cid].sense_data, 2347da3cc679SRajashekhara, Mahesh HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 2348da3cc679SRajashekhara, Mahesh ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 2349da3cc679SRajashekhara, Mahesh memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 2350da3cc679SRajashekhara, Mahesh min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 2351da3cc679SRajashekhara, Mahesh SCSI_SENSE_BUFFERSIZE)); 2352da3cc679SRajashekhara, Mahesh scsicmd->scsi_done(scsicmd); 2353da3cc679SRajashekhara, Mahesh return 1; 2354da3cc679SRajashekhara, Mahesh } 2355da3cc679SRajashekhara, Mahesh 23567a8cf29dSMark Haverkamp dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", 23571da177e4SLinus Torvalds smp_processor_id(), (unsigned long long)lba, jiffies)); 2358e8f32de5SMark Haverkamp if (aac_adapter_bounds(dev,scsicmd,lba)) 23597a8cf29dSMark Haverkamp return 0; 23601da177e4SLinus Torvalds /* 23611da177e4SLinus Torvalds * Allocate and initialize a Fib then setup a BlockWrite command 23621da177e4SLinus Torvalds */ 23636bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 23641da177e4SLinus Torvalds 23659d399cc7SSalyzyn, Mark status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua); 23661da177e4SLinus Torvalds 23671da177e4SLinus Torvalds /* 23681da177e4SLinus Torvalds * Check that the command queued to the controller 23691da177e4SLinus Torvalds */ 237077d644d4SMark Haverkamp if (status == -EINPROGRESS) { 237177d644d4SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 23721da177e4SLinus Torvalds return 0; 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds 2375bfb35aa8SMark Haverkamp printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status); 23761da177e4SLinus Torvalds /* 23771da177e4SLinus Torvalds * For some reason, the Fib didn't queue, return QUEUE_FULL 23781da177e4SLinus Torvalds */ 23791da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; 23808e0c5ebdSMark Haverkamp scsicmd->scsi_done(scsicmd); 23811da177e4SLinus Torvalds 2382bfb35aa8SMark Haverkamp aac_fib_complete(cmd_fibcontext); 2383bfb35aa8SMark Haverkamp aac_fib_free(cmd_fibcontext); 23841da177e4SLinus Torvalds return 0; 23851da177e4SLinus Torvalds } 23861da177e4SLinus Torvalds 23871da177e4SLinus Torvalds static void synchronize_callback(void *context, struct fib *fibptr) 23881da177e4SLinus Torvalds { 23891da177e4SLinus Torvalds struct aac_synchronize_reply *synchronizereply; 23901da177e4SLinus Torvalds struct scsi_cmnd *cmd; 23911da177e4SLinus Torvalds 23921da177e4SLinus Torvalds cmd = context; 23931da177e4SLinus Torvalds 239403d44337SMark Haverkamp if (!aac_valid_context(cmd, fibptr)) 239503d44337SMark Haverkamp return; 239603d44337SMark Haverkamp 23971da177e4SLinus Torvalds dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 23981da177e4SLinus Torvalds smp_processor_id(), jiffies)); 23991da177e4SLinus Torvalds BUG_ON(fibptr == NULL); 24001da177e4SLinus Torvalds 24011da177e4SLinus Torvalds 24021da177e4SLinus Torvalds synchronizereply = fib_data(fibptr); 24031da177e4SLinus Torvalds if (le32_to_cpu(synchronizereply->status) == CT_OK) 24041da177e4SLinus Torvalds cmd->result = DID_OK << 16 | 24051da177e4SLinus Torvalds COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 24061da177e4SLinus Torvalds else { 24071da177e4SLinus Torvalds struct scsi_device *sdev = cmd->device; 24081a655040SSalyzyn, Mark struct aac_dev *dev = fibptr->dev; 2409e5718774SMark Haverkamp u32 cid = sdev_id(sdev); 24101da177e4SLinus Torvalds printk(KERN_WARNING 24111da177e4SLinus Torvalds "synchronize_callback: synchronize failed, status = %d\n", 24121da177e4SLinus Torvalds le32_to_cpu(synchronizereply->status)); 24131da177e4SLinus Torvalds cmd->result = DID_OK << 16 | 24141da177e4SLinus Torvalds COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; 24158e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 24168e31e607SSalyzyn, Mark HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 24178e31e607SSalyzyn, Mark ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 24181da177e4SLinus Torvalds memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 2419b80ca4f7SFUJITA Tomonori min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 2420b80ca4f7SFUJITA Tomonori SCSI_SENSE_BUFFERSIZE)); 24211da177e4SLinus Torvalds } 24221da177e4SLinus Torvalds 2423bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 2424bfb35aa8SMark Haverkamp aac_fib_free(fibptr); 24258e0c5ebdSMark Haverkamp cmd->scsi_done(cmd); 24261da177e4SLinus Torvalds } 24271da177e4SLinus Torvalds 24289e7c349cSMark Haverkamp static int aac_synchronize(struct scsi_cmnd *scsicmd) 24291da177e4SLinus Torvalds { 24301da177e4SLinus Torvalds int status; 24311da177e4SLinus Torvalds struct fib *cmd_fibcontext; 24321da177e4SLinus Torvalds struct aac_synchronize *synchronizecmd; 24331da177e4SLinus Torvalds struct scsi_cmnd *cmd; 24341da177e4SLinus Torvalds struct scsi_device *sdev = scsicmd->device; 24351da177e4SLinus Torvalds int active = 0; 243690ee3466SMark Haverkamp struct aac_dev *aac; 2437b90f90d2SSalyzyn, Mark u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | 2438b90f90d2SSalyzyn, Mark (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 2439b90f90d2SSalyzyn, Mark u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; 24401da177e4SLinus Torvalds unsigned long flags; 24411da177e4SLinus Torvalds 24421da177e4SLinus Torvalds /* 244377d644d4SMark Haverkamp * Wait for all outstanding queued commands to complete to this 244477d644d4SMark Haverkamp * specific target (block). 24451da177e4SLinus Torvalds */ 24461da177e4SLinus Torvalds spin_lock_irqsave(&sdev->list_lock, flags); 24471da177e4SLinus Torvalds list_for_each_entry(cmd, &sdev->cmd_list, list) 2448b90f90d2SSalyzyn, Mark if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) { 2449b90f90d2SSalyzyn, Mark u64 cmnd_lba; 2450b90f90d2SSalyzyn, Mark u32 cmnd_count; 2451b90f90d2SSalyzyn, Mark 2452b90f90d2SSalyzyn, Mark if (cmd->cmnd[0] == WRITE_6) { 2453b90f90d2SSalyzyn, Mark cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) | 2454b90f90d2SSalyzyn, Mark (cmd->cmnd[2] << 8) | 2455b90f90d2SSalyzyn, Mark cmd->cmnd[3]; 2456b90f90d2SSalyzyn, Mark cmnd_count = cmd->cmnd[4]; 2457b90f90d2SSalyzyn, Mark if (cmnd_count == 0) 2458b90f90d2SSalyzyn, Mark cmnd_count = 256; 2459b90f90d2SSalyzyn, Mark } else if (cmd->cmnd[0] == WRITE_16) { 2460b90f90d2SSalyzyn, Mark cmnd_lba = ((u64)cmd->cmnd[2] << 56) | 2461b90f90d2SSalyzyn, Mark ((u64)cmd->cmnd[3] << 48) | 2462b90f90d2SSalyzyn, Mark ((u64)cmd->cmnd[4] << 40) | 2463b90f90d2SSalyzyn, Mark ((u64)cmd->cmnd[5] << 32) | 2464b90f90d2SSalyzyn, Mark ((u64)cmd->cmnd[6] << 24) | 2465b90f90d2SSalyzyn, Mark (cmd->cmnd[7] << 16) | 2466b90f90d2SSalyzyn, Mark (cmd->cmnd[8] << 8) | 2467b90f90d2SSalyzyn, Mark cmd->cmnd[9]; 2468b90f90d2SSalyzyn, Mark cmnd_count = (cmd->cmnd[10] << 24) | 2469b90f90d2SSalyzyn, Mark (cmd->cmnd[11] << 16) | 2470b90f90d2SSalyzyn, Mark (cmd->cmnd[12] << 8) | 2471b90f90d2SSalyzyn, Mark cmd->cmnd[13]; 2472b90f90d2SSalyzyn, Mark } else if (cmd->cmnd[0] == WRITE_12) { 2473b90f90d2SSalyzyn, Mark cmnd_lba = ((u64)cmd->cmnd[2] << 24) | 2474b90f90d2SSalyzyn, Mark (cmd->cmnd[3] << 16) | 2475b90f90d2SSalyzyn, Mark (cmd->cmnd[4] << 8) | 2476b90f90d2SSalyzyn, Mark cmd->cmnd[5]; 2477b90f90d2SSalyzyn, Mark cmnd_count = (cmd->cmnd[6] << 24) | 2478b90f90d2SSalyzyn, Mark (cmd->cmnd[7] << 16) | 2479b90f90d2SSalyzyn, Mark (cmd->cmnd[8] << 8) | 2480b90f90d2SSalyzyn, Mark cmd->cmnd[9]; 2481b90f90d2SSalyzyn, Mark } else if (cmd->cmnd[0] == WRITE_10) { 2482b90f90d2SSalyzyn, Mark cmnd_lba = ((u64)cmd->cmnd[2] << 24) | 2483b90f90d2SSalyzyn, Mark (cmd->cmnd[3] << 16) | 2484b90f90d2SSalyzyn, Mark (cmd->cmnd[4] << 8) | 2485b90f90d2SSalyzyn, Mark cmd->cmnd[5]; 2486b90f90d2SSalyzyn, Mark cmnd_count = (cmd->cmnd[7] << 8) | 2487b90f90d2SSalyzyn, Mark cmd->cmnd[8]; 2488b90f90d2SSalyzyn, Mark } else 2489b90f90d2SSalyzyn, Mark continue; 2490b90f90d2SSalyzyn, Mark if (((cmnd_lba + cmnd_count) < lba) || 2491b90f90d2SSalyzyn, Mark (count && ((lba + count) < cmnd_lba))) 2492b90f90d2SSalyzyn, Mark continue; 24931da177e4SLinus Torvalds ++active; 24941da177e4SLinus Torvalds break; 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 24971da177e4SLinus Torvalds spin_unlock_irqrestore(&sdev->list_lock, flags); 24981da177e4SLinus Torvalds 24991da177e4SLinus Torvalds /* 25001da177e4SLinus Torvalds * Yield the processor (requeue for later) 25011da177e4SLinus Torvalds */ 25021da177e4SLinus Torvalds if (active) 25031da177e4SLinus Torvalds return SCSI_MLQUEUE_DEVICE_BUSY; 25041da177e4SLinus Torvalds 2505f858317dSSalyzyn, Mark aac = (struct aac_dev *)sdev->host->hostdata; 25068c867b25SMark Haverkamp if (aac->in_reset) 25078c867b25SMark Haverkamp return SCSI_MLQUEUE_HOST_BUSY; 25088c867b25SMark Haverkamp 25091da177e4SLinus Torvalds /* 25107c00ffa3SMark Haverkamp * Allocate and initialize a Fib 25111da177e4SLinus Torvalds */ 251290ee3466SMark Haverkamp if (!(cmd_fibcontext = aac_fib_alloc(aac))) 25131da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 25141da177e4SLinus Torvalds 2515bfb35aa8SMark Haverkamp aac_fib_init(cmd_fibcontext); 25161da177e4SLinus Torvalds 25171da177e4SLinus Torvalds synchronizecmd = fib_data(cmd_fibcontext); 25181da177e4SLinus Torvalds synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); 25191da177e4SLinus Torvalds synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); 25209e7c349cSMark Haverkamp synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); 25211da177e4SLinus Torvalds synchronizecmd->count = 25221da177e4SLinus Torvalds cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); 25231da177e4SLinus Torvalds 25241da177e4SLinus Torvalds /* 25251da177e4SLinus Torvalds * Now send the Fib to the adapter 25261da177e4SLinus Torvalds */ 2527bfb35aa8SMark Haverkamp status = aac_fib_send(ContainerCommand, 25281da177e4SLinus Torvalds cmd_fibcontext, 25291da177e4SLinus Torvalds sizeof(struct aac_synchronize), 25301da177e4SLinus Torvalds FsaNormal, 25311da177e4SLinus Torvalds 0, 1, 25321da177e4SLinus Torvalds (fib_callback)synchronize_callback, 25331da177e4SLinus Torvalds (void *)scsicmd); 25341da177e4SLinus Torvalds 25351da177e4SLinus Torvalds /* 25361da177e4SLinus Torvalds * Check that the command queued to the controller 25371da177e4SLinus Torvalds */ 253877d644d4SMark Haverkamp if (status == -EINPROGRESS) { 253977d644d4SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 25401da177e4SLinus Torvalds return 0; 254177d644d4SMark Haverkamp } 25421da177e4SLinus Torvalds 25431da177e4SLinus Torvalds printk(KERN_WARNING 2544bfb35aa8SMark Haverkamp "aac_synchronize: aac_fib_send failed with status: %d.\n", status); 2545bfb35aa8SMark Haverkamp aac_fib_complete(cmd_fibcontext); 2546bfb35aa8SMark Haverkamp aac_fib_free(cmd_fibcontext); 25471da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 25481da177e4SLinus Torvalds } 25491da177e4SLinus Torvalds 2550655d722cSMark Salyzyn static void aac_start_stop_callback(void *context, struct fib *fibptr) 2551655d722cSMark Salyzyn { 2552655d722cSMark Salyzyn struct scsi_cmnd *scsicmd = context; 2553655d722cSMark Salyzyn 2554655d722cSMark Salyzyn if (!aac_valid_context(scsicmd, fibptr)) 2555655d722cSMark Salyzyn return; 2556655d722cSMark Salyzyn 2557655d722cSMark Salyzyn BUG_ON(fibptr == NULL); 2558655d722cSMark Salyzyn 2559655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 2560655d722cSMark Salyzyn 2561655d722cSMark Salyzyn aac_fib_complete(fibptr); 2562655d722cSMark Salyzyn aac_fib_free(fibptr); 2563655d722cSMark Salyzyn scsicmd->scsi_done(scsicmd); 2564655d722cSMark Salyzyn } 2565655d722cSMark Salyzyn 2566655d722cSMark Salyzyn static int aac_start_stop(struct scsi_cmnd *scsicmd) 2567655d722cSMark Salyzyn { 2568655d722cSMark Salyzyn int status; 2569655d722cSMark Salyzyn struct fib *cmd_fibcontext; 2570655d722cSMark Salyzyn struct aac_power_management *pmcmd; 2571655d722cSMark Salyzyn struct scsi_device *sdev = scsicmd->device; 2572655d722cSMark Salyzyn struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; 2573655d722cSMark Salyzyn 2574655d722cSMark Salyzyn if (!(aac->supplement_adapter_info.SupportedOptions2 & 2575655d722cSMark Salyzyn AAC_OPTION_POWER_MANAGEMENT)) { 2576655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 2577655d722cSMark Salyzyn SAM_STAT_GOOD; 2578655d722cSMark Salyzyn scsicmd->scsi_done(scsicmd); 2579655d722cSMark Salyzyn return 0; 2580655d722cSMark Salyzyn } 2581655d722cSMark Salyzyn 2582655d722cSMark Salyzyn if (aac->in_reset) 2583655d722cSMark Salyzyn return SCSI_MLQUEUE_HOST_BUSY; 2584655d722cSMark Salyzyn 2585655d722cSMark Salyzyn /* 2586655d722cSMark Salyzyn * Allocate and initialize a Fib 2587655d722cSMark Salyzyn */ 25886bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd); 2589655d722cSMark Salyzyn 2590655d722cSMark Salyzyn aac_fib_init(cmd_fibcontext); 2591655d722cSMark Salyzyn 2592655d722cSMark Salyzyn pmcmd = fib_data(cmd_fibcontext); 2593655d722cSMark Salyzyn pmcmd->command = cpu_to_le32(VM_ContainerConfig); 2594655d722cSMark Salyzyn pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT); 2595655d722cSMark Salyzyn /* Eject bit ignored, not relevant */ 2596655d722cSMark Salyzyn pmcmd->sub = (scsicmd->cmnd[4] & 1) ? 2597655d722cSMark Salyzyn cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT); 2598655d722cSMark Salyzyn pmcmd->cid = cpu_to_le32(sdev_id(sdev)); 2599655d722cSMark Salyzyn pmcmd->parm = (scsicmd->cmnd[1] & 1) ? 2600655d722cSMark Salyzyn cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0; 2601655d722cSMark Salyzyn 2602655d722cSMark Salyzyn /* 2603655d722cSMark Salyzyn * Now send the Fib to the adapter 2604655d722cSMark Salyzyn */ 2605655d722cSMark Salyzyn status = aac_fib_send(ContainerCommand, 2606655d722cSMark Salyzyn cmd_fibcontext, 2607655d722cSMark Salyzyn sizeof(struct aac_power_management), 2608655d722cSMark Salyzyn FsaNormal, 2609655d722cSMark Salyzyn 0, 1, 2610655d722cSMark Salyzyn (fib_callback)aac_start_stop_callback, 2611655d722cSMark Salyzyn (void *)scsicmd); 2612655d722cSMark Salyzyn 2613655d722cSMark Salyzyn /* 2614655d722cSMark Salyzyn * Check that the command queued to the controller 2615655d722cSMark Salyzyn */ 2616655d722cSMark Salyzyn if (status == -EINPROGRESS) { 2617655d722cSMark Salyzyn scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 2618655d722cSMark Salyzyn return 0; 2619655d722cSMark Salyzyn } 2620655d722cSMark Salyzyn 2621655d722cSMark Salyzyn aac_fib_complete(cmd_fibcontext); 2622655d722cSMark Salyzyn aac_fib_free(cmd_fibcontext); 2623655d722cSMark Salyzyn return SCSI_MLQUEUE_HOST_BUSY; 2624655d722cSMark Salyzyn } 2625655d722cSMark Salyzyn 26261da177e4SLinus Torvalds /** 26271da177e4SLinus Torvalds * aac_scsi_cmd() - Process SCSI command 26281da177e4SLinus Torvalds * @scsicmd: SCSI command block 26291da177e4SLinus Torvalds * 26301da177e4SLinus Torvalds * Emulate a SCSI command and queue the required request for the 26311da177e4SLinus Torvalds * aacraid firmware. 26321da177e4SLinus Torvalds */ 26331da177e4SLinus Torvalds 26341da177e4SLinus Torvalds int aac_scsi_cmd(struct scsi_cmnd * scsicmd) 26351da177e4SLinus Torvalds { 2636ab5d129fSRaghava Aditya Renukunta u32 cid, bus; 26371da177e4SLinus Torvalds struct Scsi_Host *host = scsicmd->device->host; 26381da177e4SLinus Torvalds struct aac_dev *dev = (struct aac_dev *)host->hostdata; 26391da177e4SLinus Torvalds struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; 26401da177e4SLinus Torvalds 264190ee3466SMark Haverkamp if (fsa_dev_ptr == NULL) 264290ee3466SMark Haverkamp return -1; 26431da177e4SLinus Torvalds /* 26441da177e4SLinus Torvalds * If the bus, id or lun is out of range, return fail 26451da177e4SLinus Torvalds * Test does not apply to ID 16, the pseudo id for the controller 26461da177e4SLinus Torvalds * itself. 26471da177e4SLinus Torvalds */ 26481a655040SSalyzyn, Mark cid = scmd_id(scsicmd); 26491a655040SSalyzyn, Mark if (cid != host->this_id) { 26501a655040SSalyzyn, Mark if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) { 26511a655040SSalyzyn, Mark if((cid >= dev->maximum_num_containers) || 2652e5718774SMark Haverkamp (scsicmd->device->lun != 0)) { 26531da177e4SLinus Torvalds scsicmd->result = DID_NO_CONNECT << 16; 2654c4e2fbcaSRaghava Aditya Renukunta goto scsi_done_ret; 26551da177e4SLinus Torvalds } 26561da177e4SLinus Torvalds 26571da177e4SLinus Torvalds /* 26581da177e4SLinus Torvalds * If the target container doesn't exist, it may have 26591da177e4SLinus Torvalds * been newly created 26601da177e4SLinus Torvalds */ 2661655d722cSMark Salyzyn if (((fsa_dev_ptr[cid].valid & 1) == 0) || 2662655d722cSMark Salyzyn (fsa_dev_ptr[cid].sense_data.sense_key == 2663655d722cSMark Salyzyn NOT_READY)) { 26641da177e4SLinus Torvalds switch (scsicmd->cmnd[0]) { 2665eb846d9fSHannes Reinecke case SERVICE_ACTION_IN_16: 26667a8cf29dSMark Haverkamp if (!(dev->raw_io_interface) || 26677a8cf29dSMark Haverkamp !(dev->raw_io_64) || 26687a8cf29dSMark Haverkamp ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) 26697a8cf29dSMark Haverkamp break; 26701da177e4SLinus Torvalds case INQUIRY: 26711da177e4SLinus Torvalds case READ_CAPACITY: 26721da177e4SLinus Torvalds case TEST_UNIT_READY: 26738c867b25SMark Haverkamp if (dev->in_reset) 26748c867b25SMark Haverkamp return -1; 2675fe76df42SMark Haverkamp return _aac_probe_container(scsicmd, 2676fe76df42SMark Haverkamp aac_probe_container_callback2); 26771da177e4SLinus Torvalds default: 26781da177e4SLinus Torvalds break; 26791da177e4SLinus Torvalds } 26801da177e4SLinus Torvalds } 26811da177e4SLinus Torvalds } else { /* check for physical non-dasd devices */ 2682ab5d129fSRaghava Aditya Renukunta bus = aac_logical_to_phys(scmd_channel(scsicmd)); 2683ab5d129fSRaghava Aditya Renukunta if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && 2684ab5d129fSRaghava Aditya Renukunta (dev->hba_map[bus][cid].expose 2685ab5d129fSRaghava Aditya Renukunta == AAC_HIDE_DISK)){ 2686ab5d129fSRaghava Aditya Renukunta if (scsicmd->cmnd[0] == INQUIRY) { 2687ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_NO_CONNECT << 16; 2688ab5d129fSRaghava Aditya Renukunta goto scsi_done_ret; 2689ab5d129fSRaghava Aditya Renukunta } 2690ab5d129fSRaghava Aditya Renukunta } 2691ab5d129fSRaghava Aditya Renukunta 2692ab5d129fSRaghava Aditya Renukunta if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && 2693ab5d129fSRaghava Aditya Renukunta dev->hba_map[bus][cid].devtype 2694ab5d129fSRaghava Aditya Renukunta == AAC_DEVTYPE_NATIVE_RAW) { 2695ab5d129fSRaghava Aditya Renukunta if (dev->in_reset) 2696ab5d129fSRaghava Aditya Renukunta return -1; 2697ab5d129fSRaghava Aditya Renukunta return aac_send_hba_fib(scsicmd); 2698ab5d129fSRaghava Aditya Renukunta } else if (dev->nondasd_support || expose_physicals || 2699cb1042f2SSalyzyn, Mark dev->jbod) { 27008c867b25SMark Haverkamp if (dev->in_reset) 27018c867b25SMark Haverkamp return -1; 27021da177e4SLinus Torvalds return aac_send_srb_fib(scsicmd); 27031da177e4SLinus Torvalds } else { 27041da177e4SLinus Torvalds scsicmd->result = DID_NO_CONNECT << 16; 2705c4e2fbcaSRaghava Aditya Renukunta goto scsi_done_ret; 27061da177e4SLinus Torvalds } 27071da177e4SLinus Torvalds } 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds /* 27101da177e4SLinus Torvalds * else Command for the controller itself 27111da177e4SLinus Torvalds */ 27121da177e4SLinus Torvalds else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */ 27131da177e4SLinus Torvalds (scsicmd->cmnd[0] != TEST_UNIT_READY)) 27141da177e4SLinus Torvalds { 27151da177e4SLinus Torvalds dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); 27161da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; 27178e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 27188e31e607SSalyzyn, Mark ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, 27198e31e607SSalyzyn, Mark ASENCODE_INVALID_COMMAND, 0, 0); 27201da177e4SLinus Torvalds memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 27213ace426fSSalyzyn, Mark min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 27223ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE)); 2723c4e2fbcaSRaghava Aditya Renukunta goto scsi_done_ret; 27241da177e4SLinus Torvalds } 27251da177e4SLinus Torvalds 27261da177e4SLinus Torvalds switch (scsicmd->cmnd[0]) { 2727c4e2fbcaSRaghava Aditya Renukunta case READ_6: 2728c4e2fbcaSRaghava Aditya Renukunta case READ_10: 2729c4e2fbcaSRaghava Aditya Renukunta case READ_12: 2730c4e2fbcaSRaghava Aditya Renukunta case READ_16: 2731c4e2fbcaSRaghava Aditya Renukunta if (dev->in_reset) 2732c4e2fbcaSRaghava Aditya Renukunta return -1; 2733c4e2fbcaSRaghava Aditya Renukunta return aac_read(scsicmd); 2734c4e2fbcaSRaghava Aditya Renukunta 2735c4e2fbcaSRaghava Aditya Renukunta case WRITE_6: 2736c4e2fbcaSRaghava Aditya Renukunta case WRITE_10: 2737c4e2fbcaSRaghava Aditya Renukunta case WRITE_12: 2738c4e2fbcaSRaghava Aditya Renukunta case WRITE_16: 2739c4e2fbcaSRaghava Aditya Renukunta if (dev->in_reset) 2740c4e2fbcaSRaghava Aditya Renukunta return -1; 2741c4e2fbcaSRaghava Aditya Renukunta return aac_write(scsicmd); 2742c4e2fbcaSRaghava Aditya Renukunta 2743c4e2fbcaSRaghava Aditya Renukunta case SYNCHRONIZE_CACHE: 2744c4e2fbcaSRaghava Aditya Renukunta if (((aac_cache & 6) == 6) && dev->cache_protected) { 2745c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 2746c4e2fbcaSRaghava Aditya Renukunta break; 2747c4e2fbcaSRaghava Aditya Renukunta } 2748c4e2fbcaSRaghava Aditya Renukunta /* Issue FIB to tell Firmware to flush it's cache */ 2749c4e2fbcaSRaghava Aditya Renukunta if ((aac_cache & 6) != 2) 2750c4e2fbcaSRaghava Aditya Renukunta return aac_synchronize(scsicmd); 27511da177e4SLinus Torvalds case INQUIRY: 27521da177e4SLinus Torvalds { 27533b2946ccSMark Haverkamp struct inquiry_data inq_data; 27541da177e4SLinus Torvalds 27551a655040SSalyzyn, Mark dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); 27563b2946ccSMark Haverkamp memset(&inq_data, 0, sizeof (struct inquiry_data)); 27571da177e4SLinus Torvalds 2758d8e96507SLeubner, Achim if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) { 275988e2f98eSSalyzyn, Mark char *arr = (char *)&inq_data; 276088e2f98eSSalyzyn, Mark 276188e2f98eSSalyzyn, Mark /* EVPD bit set */ 276288e2f98eSSalyzyn, Mark arr[0] = (scmd_id(scsicmd) == host->this_id) ? 276388e2f98eSSalyzyn, Mark INQD_PDT_PROC : INQD_PDT_DA; 276488e2f98eSSalyzyn, Mark if (scsicmd->cmnd[2] == 0) { 276588e2f98eSSalyzyn, Mark /* supported vital product data pages */ 27665d910649SMahesh Rajashekhara arr[3] = 3; 276788e2f98eSSalyzyn, Mark arr[4] = 0x0; 276888e2f98eSSalyzyn, Mark arr[5] = 0x80; 27695d910649SMahesh Rajashekhara arr[6] = 0x83; 277088e2f98eSSalyzyn, Mark arr[1] = scsicmd->cmnd[2]; 2771d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, &inq_data, 277288e2f98eSSalyzyn, Mark sizeof(inq_data)); 2773c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 277488e2f98eSSalyzyn, Mark } else if (scsicmd->cmnd[2] == 0x80) { 277588e2f98eSSalyzyn, Mark /* unit serial number page */ 277688e2f98eSSalyzyn, Mark arr[3] = setinqserial(dev, &arr[4], 277788e2f98eSSalyzyn, Mark scmd_id(scsicmd)); 277888e2f98eSSalyzyn, Mark arr[1] = scsicmd->cmnd[2]; 2779d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, &inq_data, 278088e2f98eSSalyzyn, Mark sizeof(inq_data)); 2781d8e96507SLeubner, Achim if (aac_wwn != 2) 2782d8e96507SLeubner, Achim return aac_get_container_serial( 2783d8e96507SLeubner, Achim scsicmd); 2784c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 27855d910649SMahesh Rajashekhara } else if (scsicmd->cmnd[2] == 0x83) { 27865d910649SMahesh Rajashekhara /* vpd page 0x83 - Device Identification Page */ 27875d910649SMahesh Rajashekhara char *sno = (char *)&inq_data; 27885d910649SMahesh Rajashekhara sno[3] = setinqserial(dev, &sno[4], 27895d910649SMahesh Rajashekhara scmd_id(scsicmd)); 27905d910649SMahesh Rajashekhara if (aac_wwn != 2) 27915d910649SMahesh Rajashekhara return aac_get_container_serial( 27925d910649SMahesh Rajashekhara scsicmd); 2793c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 279488e2f98eSSalyzyn, Mark } else { 279588e2f98eSSalyzyn, Mark /* vpd page not implemented */ 279688e2f98eSSalyzyn, Mark scsicmd->result = DID_OK << 16 | 279788e2f98eSSalyzyn, Mark COMMAND_COMPLETE << 8 | 279888e2f98eSSalyzyn, Mark SAM_STAT_CHECK_CONDITION; 27998e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 28008e31e607SSalyzyn, Mark ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, 28018e31e607SSalyzyn, Mark ASENCODE_NO_SENSE, 7, 2); 280288e2f98eSSalyzyn, Mark memcpy(scsicmd->sense_buffer, 280388e2f98eSSalyzyn, Mark &dev->fsa_dev[cid].sense_data, 28043ace426fSSalyzyn, Mark min_t(size_t, 28053ace426fSSalyzyn, Mark sizeof(dev->fsa_dev[cid].sense_data), 28063ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE)); 280788e2f98eSSalyzyn, Mark } 2808c4e2fbcaSRaghava Aditya Renukunta break; 280988e2f98eSSalyzyn, Mark } 28103b2946ccSMark Haverkamp inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ 28113b2946ccSMark Haverkamp 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 */ 28123b2946ccSMark Haverkamp inq_data.inqd_len = 31; 28131da177e4SLinus Torvalds /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ 28143b2946ccSMark Haverkamp inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ 28151da177e4SLinus Torvalds /* 28161da177e4SLinus Torvalds * Set the Vendor, Product, and Revision Level 28171da177e4SLinus Torvalds * see: <vendor>.c i.e. aac.c 28181da177e4SLinus Torvalds */ 28191a655040SSalyzyn, Mark if (cid == host->this_id) { 28206391a113STobias Klauser setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types)); 28213b2946ccSMark Haverkamp inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ 2822d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, &inq_data, 2823d4345028SFUJITA Tomonori sizeof(inq_data)); 2824c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 2825c4e2fbcaSRaghava Aditya Renukunta break; 28261da177e4SLinus Torvalds } 28278c867b25SMark Haverkamp if (dev->in_reset) 28288c867b25SMark Haverkamp return -1; 2829794d0601SMark Haverkamp setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); 28303b2946ccSMark Haverkamp inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ 2831d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); 28329e7c349cSMark Haverkamp return aac_get_container_name(scsicmd); 28331da177e4SLinus Torvalds } 2834eb846d9fSHannes Reinecke case SERVICE_ACTION_IN_16: 28357a8cf29dSMark Haverkamp if (!(dev->raw_io_interface) || 28367a8cf29dSMark Haverkamp !(dev->raw_io_64) || 28377a8cf29dSMark Haverkamp ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) 28387a8cf29dSMark Haverkamp break; 28397a8cf29dSMark Haverkamp { 28407a8cf29dSMark Haverkamp u64 capacity; 284107ce5ebaSMark Haverkamp char cp[13]; 2842b271f1c8SFUJITA Tomonori unsigned int alloc_len; 28437a8cf29dSMark Haverkamp 28447a8cf29dSMark Haverkamp dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); 28457a8cf29dSMark Haverkamp capacity = fsa_dev_ptr[cid].size - 1; 28467a8cf29dSMark Haverkamp cp[0] = (capacity >> 56) & 0xff; 28477a8cf29dSMark Haverkamp cp[1] = (capacity >> 48) & 0xff; 28487a8cf29dSMark Haverkamp cp[2] = (capacity >> 40) & 0xff; 28497a8cf29dSMark Haverkamp cp[3] = (capacity >> 32) & 0xff; 28507a8cf29dSMark Haverkamp cp[4] = (capacity >> 24) & 0xff; 28517a8cf29dSMark Haverkamp cp[5] = (capacity >> 16) & 0xff; 28527a8cf29dSMark Haverkamp cp[6] = (capacity >> 8) & 0xff; 28537a8cf29dSMark Haverkamp cp[7] = (capacity >> 0) & 0xff; 2854b836439fSMahesh Rajashekhara cp[8] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff; 2855b836439fSMahesh Rajashekhara cp[9] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 2856b836439fSMahesh Rajashekhara cp[10] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 2857b836439fSMahesh Rajashekhara cp[11] = (fsa_dev_ptr[cid].block_size) & 0xff; 285807ce5ebaSMark Haverkamp cp[12] = 0; 285907ce5ebaSMark Haverkamp 2860b271f1c8SFUJITA Tomonori alloc_len = ((scsicmd->cmnd[10] << 24) 2861b271f1c8SFUJITA Tomonori + (scsicmd->cmnd[11] << 16) 2862b271f1c8SFUJITA Tomonori + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]); 2863b271f1c8SFUJITA Tomonori 2864b271f1c8SFUJITA Tomonori alloc_len = min_t(size_t, alloc_len, sizeof(cp)); 2865d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len); 2866b271f1c8SFUJITA Tomonori if (alloc_len < scsi_bufflen(scsicmd)) 2867b271f1c8SFUJITA Tomonori scsi_set_resid(scsicmd, 2868b271f1c8SFUJITA Tomonori scsi_bufflen(scsicmd) - alloc_len); 28697a8cf29dSMark Haverkamp 28707a8cf29dSMark Haverkamp /* Do not cache partition table for arrays */ 28717a8cf29dSMark Haverkamp scsicmd->device->removable = 1; 28727a8cf29dSMark Haverkamp 2873c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 2874c4e2fbcaSRaghava Aditya Renukunta break; 28757a8cf29dSMark Haverkamp } 28767a8cf29dSMark Haverkamp 28771da177e4SLinus Torvalds case READ_CAPACITY: 28781da177e4SLinus Torvalds { 28791da177e4SLinus Torvalds u32 capacity; 28803b2946ccSMark Haverkamp char cp[8]; 28811da177e4SLinus Torvalds 28821da177e4SLinus Torvalds dprintk((KERN_DEBUG "READ CAPACITY command.\n")); 28837a8cf29dSMark Haverkamp if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 28841da177e4SLinus Torvalds capacity = fsa_dev_ptr[cid].size - 1; 28851da177e4SLinus Torvalds else 28861da177e4SLinus Torvalds capacity = (u32)-1; 28873b2946ccSMark Haverkamp 28881da177e4SLinus Torvalds cp[0] = (capacity >> 24) & 0xff; 28891da177e4SLinus Torvalds cp[1] = (capacity >> 16) & 0xff; 28901da177e4SLinus Torvalds cp[2] = (capacity >> 8) & 0xff; 28911da177e4SLinus Torvalds cp[3] = (capacity >> 0) & 0xff; 2892b836439fSMahesh Rajashekhara cp[4] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff; 2893b836439fSMahesh Rajashekhara cp[5] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 2894b836439fSMahesh Rajashekhara cp[6] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 2895b836439fSMahesh Rajashekhara cp[7] = (fsa_dev_ptr[cid].block_size) & 0xff; 2896d4345028SFUJITA Tomonori scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); 28977a8cf29dSMark Haverkamp /* Do not cache partition table for arrays */ 28987a8cf29dSMark Haverkamp scsicmd->device->removable = 1; 2899c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 2900c4e2fbcaSRaghava Aditya Renukunta break; 29011da177e4SLinus Torvalds } 29021da177e4SLinus Torvalds 29031da177e4SLinus Torvalds case MODE_SENSE: 29041da177e4SLinus Torvalds { 29059d399cc7SSalyzyn, Mark int mode_buf_length = 4; 2906b836439fSMahesh Rajashekhara u32 capacity; 2907b836439fSMahesh Rajashekhara aac_modep_data mpd; 2908b836439fSMahesh Rajashekhara 2909b836439fSMahesh Rajashekhara if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 2910b836439fSMahesh Rajashekhara capacity = fsa_dev_ptr[cid].size - 1; 2911b836439fSMahesh Rajashekhara else 2912b836439fSMahesh Rajashekhara capacity = (u32)-1; 29131da177e4SLinus Torvalds 29141da177e4SLinus Torvalds dprintk((KERN_DEBUG "MODE SENSE command.\n")); 2915b836439fSMahesh Rajashekhara memset((char *)&mpd, 0, sizeof(aac_modep_data)); 2916b836439fSMahesh Rajashekhara 2917b836439fSMahesh Rajashekhara /* Mode data length */ 2918b836439fSMahesh Rajashekhara mpd.hd.data_length = sizeof(mpd.hd) - 1; 2919b836439fSMahesh Rajashekhara /* Medium type - default */ 2920b836439fSMahesh Rajashekhara mpd.hd.med_type = 0; 2921b836439fSMahesh Rajashekhara /* Device-specific param, 29229d399cc7SSalyzyn, Mark bit 8: 0/1 = write enabled/protected 29239d399cc7SSalyzyn, Mark bit 4: 0/1 = FUA enabled */ 2924b836439fSMahesh Rajashekhara mpd.hd.dev_par = 0; 2925b836439fSMahesh Rajashekhara 292695e852e1SSalyzyn, Mark if (dev->raw_io_interface && ((aac_cache & 5) != 1)) 2927b836439fSMahesh Rajashekhara mpd.hd.dev_par = 0x10; 2928b836439fSMahesh Rajashekhara if (scsicmd->cmnd[1] & 0x8) 2929b836439fSMahesh Rajashekhara mpd.hd.bd_length = 0; /* Block descriptor length */ 2930b836439fSMahesh Rajashekhara else { 2931b836439fSMahesh Rajashekhara mpd.hd.bd_length = sizeof(mpd.bd); 2932b836439fSMahesh Rajashekhara mpd.hd.data_length += mpd.hd.bd_length; 2933b836439fSMahesh Rajashekhara mpd.bd.block_length[0] = 2934b836439fSMahesh Rajashekhara (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 2935b836439fSMahesh Rajashekhara mpd.bd.block_length[1] = 2936b836439fSMahesh Rajashekhara (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 2937b836439fSMahesh Rajashekhara mpd.bd.block_length[2] = 2938b836439fSMahesh Rajashekhara fsa_dev_ptr[cid].block_size & 0xff; 29395d910649SMahesh Rajashekhara 29405d910649SMahesh Rajashekhara mpd.mpc_buf[0] = scsicmd->cmnd[2]; 29415d910649SMahesh Rajashekhara if (scsicmd->cmnd[2] == 0x1C) { 29425d910649SMahesh Rajashekhara /* page length */ 29435d910649SMahesh Rajashekhara mpd.mpc_buf[1] = 0xa; 29445d910649SMahesh Rajashekhara /* Mode data length */ 29455d910649SMahesh Rajashekhara mpd.hd.data_length = 23; 29465d910649SMahesh Rajashekhara } else { 29475d910649SMahesh Rajashekhara /* Mode data length */ 29485d910649SMahesh Rajashekhara mpd.hd.data_length = 15; 29495d910649SMahesh Rajashekhara } 29505d910649SMahesh Rajashekhara 2951b836439fSMahesh Rajashekhara if (capacity > 0xffffff) { 2952b836439fSMahesh Rajashekhara mpd.bd.block_count[0] = 0xff; 2953b836439fSMahesh Rajashekhara mpd.bd.block_count[1] = 0xff; 2954b836439fSMahesh Rajashekhara mpd.bd.block_count[2] = 0xff; 2955b836439fSMahesh Rajashekhara } else { 2956b836439fSMahesh Rajashekhara mpd.bd.block_count[0] = (capacity >> 16) & 0xff; 2957b836439fSMahesh Rajashekhara mpd.bd.block_count[1] = (capacity >> 8) & 0xff; 2958b836439fSMahesh Rajashekhara mpd.bd.block_count[2] = capacity & 0xff; 2959b836439fSMahesh Rajashekhara } 2960b836439fSMahesh Rajashekhara } 29619d399cc7SSalyzyn, Mark if (((scsicmd->cmnd[2] & 0x3f) == 8) || 29629d399cc7SSalyzyn, Mark ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { 2963b836439fSMahesh Rajashekhara mpd.hd.data_length += 3; 2964b836439fSMahesh Rajashekhara mpd.mpc_buf[0] = 8; 2965b836439fSMahesh Rajashekhara mpd.mpc_buf[1] = 1; 2966b836439fSMahesh Rajashekhara mpd.mpc_buf[2] = ((aac_cache & 6) == 2) 296795e852e1SSalyzyn, Mark ? 0 : 0x04; /* WCE */ 2968b836439fSMahesh Rajashekhara mode_buf_length = sizeof(mpd); 29695d910649SMahesh Rajashekhara } 29705d910649SMahesh Rajashekhara 29719d399cc7SSalyzyn, Mark if (mode_buf_length > scsicmd->cmnd[4]) 29729d399cc7SSalyzyn, Mark mode_buf_length = scsicmd->cmnd[4]; 29735d910649SMahesh Rajashekhara else 29745d910649SMahesh Rajashekhara mode_buf_length = sizeof(mpd); 2975b836439fSMahesh Rajashekhara scsi_sg_copy_from_buffer(scsicmd, 2976b836439fSMahesh Rajashekhara (char *)&mpd, 2977b836439fSMahesh Rajashekhara mode_buf_length); 2978c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 2979c4e2fbcaSRaghava Aditya Renukunta break; 29801da177e4SLinus Torvalds } 29811da177e4SLinus Torvalds case MODE_SENSE_10: 29821da177e4SLinus Torvalds { 2983b836439fSMahesh Rajashekhara u32 capacity; 29849d399cc7SSalyzyn, Mark int mode_buf_length = 8; 2985b836439fSMahesh Rajashekhara aac_modep10_data mpd10; 2986b836439fSMahesh Rajashekhara 2987b836439fSMahesh Rajashekhara if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 2988b836439fSMahesh Rajashekhara capacity = fsa_dev_ptr[cid].size - 1; 2989b836439fSMahesh Rajashekhara else 2990b836439fSMahesh Rajashekhara capacity = (u32)-1; 29911da177e4SLinus Torvalds 29921da177e4SLinus Torvalds dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); 2993b836439fSMahesh Rajashekhara memset((char *)&mpd10, 0, sizeof(aac_modep10_data)); 2994b836439fSMahesh Rajashekhara /* Mode data length (MSB) */ 2995b836439fSMahesh Rajashekhara mpd10.hd.data_length[0] = 0; 2996b836439fSMahesh Rajashekhara /* Mode data length (LSB) */ 2997b836439fSMahesh Rajashekhara mpd10.hd.data_length[1] = sizeof(mpd10.hd) - 1; 2998b836439fSMahesh Rajashekhara /* Medium type - default */ 2999b836439fSMahesh Rajashekhara mpd10.hd.med_type = 0; 3000b836439fSMahesh Rajashekhara /* Device-specific param, 30019d399cc7SSalyzyn, Mark bit 8: 0/1 = write enabled/protected 30029d399cc7SSalyzyn, Mark bit 4: 0/1 = FUA enabled */ 3003b836439fSMahesh Rajashekhara mpd10.hd.dev_par = 0; 3004b836439fSMahesh Rajashekhara 300595e852e1SSalyzyn, Mark if (dev->raw_io_interface && ((aac_cache & 5) != 1)) 3006b836439fSMahesh Rajashekhara mpd10.hd.dev_par = 0x10; 3007b836439fSMahesh Rajashekhara mpd10.hd.rsrvd[0] = 0; /* reserved */ 3008b836439fSMahesh Rajashekhara mpd10.hd.rsrvd[1] = 0; /* reserved */ 3009b836439fSMahesh Rajashekhara if (scsicmd->cmnd[1] & 0x8) { 3010b836439fSMahesh Rajashekhara /* Block descriptor length (MSB) */ 3011b836439fSMahesh Rajashekhara mpd10.hd.bd_length[0] = 0; 3012b836439fSMahesh Rajashekhara /* Block descriptor length (LSB) */ 3013b836439fSMahesh Rajashekhara mpd10.hd.bd_length[1] = 0; 3014b836439fSMahesh Rajashekhara } else { 3015b836439fSMahesh Rajashekhara mpd10.hd.bd_length[0] = 0; 3016b836439fSMahesh Rajashekhara mpd10.hd.bd_length[1] = sizeof(mpd10.bd); 3017b836439fSMahesh Rajashekhara 3018b836439fSMahesh Rajashekhara mpd10.hd.data_length[1] += mpd10.hd.bd_length[1]; 3019b836439fSMahesh Rajashekhara 3020b836439fSMahesh Rajashekhara mpd10.bd.block_length[0] = 3021b836439fSMahesh Rajashekhara (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 3022b836439fSMahesh Rajashekhara mpd10.bd.block_length[1] = 3023b836439fSMahesh Rajashekhara (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 3024b836439fSMahesh Rajashekhara mpd10.bd.block_length[2] = 3025b836439fSMahesh Rajashekhara fsa_dev_ptr[cid].block_size & 0xff; 3026b836439fSMahesh Rajashekhara 3027b836439fSMahesh Rajashekhara if (capacity > 0xffffff) { 3028b836439fSMahesh Rajashekhara mpd10.bd.block_count[0] = 0xff; 3029b836439fSMahesh Rajashekhara mpd10.bd.block_count[1] = 0xff; 3030b836439fSMahesh Rajashekhara mpd10.bd.block_count[2] = 0xff; 3031b836439fSMahesh Rajashekhara } else { 3032b836439fSMahesh Rajashekhara mpd10.bd.block_count[0] = 3033b836439fSMahesh Rajashekhara (capacity >> 16) & 0xff; 3034b836439fSMahesh Rajashekhara mpd10.bd.block_count[1] = 3035b836439fSMahesh Rajashekhara (capacity >> 8) & 0xff; 3036b836439fSMahesh Rajashekhara mpd10.bd.block_count[2] = 3037b836439fSMahesh Rajashekhara capacity & 0xff; 3038b836439fSMahesh Rajashekhara } 3039b836439fSMahesh Rajashekhara } 30409d399cc7SSalyzyn, Mark if (((scsicmd->cmnd[2] & 0x3f) == 8) || 30419d399cc7SSalyzyn, Mark ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { 3042b836439fSMahesh Rajashekhara mpd10.hd.data_length[1] += 3; 3043b836439fSMahesh Rajashekhara mpd10.mpc_buf[0] = 8; 3044b836439fSMahesh Rajashekhara mpd10.mpc_buf[1] = 1; 3045b836439fSMahesh Rajashekhara mpd10.mpc_buf[2] = ((aac_cache & 6) == 2) 304695e852e1SSalyzyn, Mark ? 0 : 0x04; /* WCE */ 3047b836439fSMahesh Rajashekhara mode_buf_length = sizeof(mpd10); 30489d399cc7SSalyzyn, Mark if (mode_buf_length > scsicmd->cmnd[8]) 30499d399cc7SSalyzyn, Mark mode_buf_length = scsicmd->cmnd[8]; 30509d399cc7SSalyzyn, Mark } 3051b836439fSMahesh Rajashekhara scsi_sg_copy_from_buffer(scsicmd, 3052b836439fSMahesh Rajashekhara (char *)&mpd10, 3053b836439fSMahesh Rajashekhara mode_buf_length); 30541da177e4SLinus Torvalds 3055c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 3056c4e2fbcaSRaghava Aditya Renukunta break; 30571da177e4SLinus Torvalds } 30581da177e4SLinus Torvalds case REQUEST_SENSE: 30591da177e4SLinus Torvalds dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); 3060c4e2fbcaSRaghava Aditya Renukunta memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 3061c4e2fbcaSRaghava Aditya Renukunta sizeof(struct sense_data)); 3062c4e2fbcaSRaghava Aditya Renukunta memset(&dev->fsa_dev[cid].sense_data, 0, 3063c4e2fbcaSRaghava Aditya Renukunta sizeof(struct sense_data)); 3064c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 3065c4e2fbcaSRaghava Aditya Renukunta break; 30661da177e4SLinus Torvalds 30671da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 30681da177e4SLinus Torvalds dprintk((KERN_DEBUG "LOCK command.\n")); 30691da177e4SLinus Torvalds if (scsicmd->cmnd[4]) 30701da177e4SLinus Torvalds fsa_dev_ptr[cid].locked = 1; 30711da177e4SLinus Torvalds else 30721da177e4SLinus Torvalds fsa_dev_ptr[cid].locked = 0; 30731da177e4SLinus Torvalds 3074c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 3075c4e2fbcaSRaghava Aditya Renukunta break; 30761da177e4SLinus Torvalds /* 30771da177e4SLinus Torvalds * These commands are all No-Ops 30781da177e4SLinus Torvalds */ 30791da177e4SLinus Torvalds case TEST_UNIT_READY: 3080655d722cSMark Salyzyn if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) { 3081655d722cSMark Salyzyn scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 3082655d722cSMark Salyzyn SAM_STAT_CHECK_CONDITION; 3083655d722cSMark Salyzyn set_sense(&dev->fsa_dev[cid].sense_data, 3084655d722cSMark Salyzyn NOT_READY, SENCODE_BECOMING_READY, 3085655d722cSMark Salyzyn ASENCODE_BECOMING_READY, 0, 0); 3086655d722cSMark Salyzyn memcpy(scsicmd->sense_buffer, 3087655d722cSMark Salyzyn &dev->fsa_dev[cid].sense_data, 3088655d722cSMark Salyzyn min_t(size_t, 3089655d722cSMark Salyzyn sizeof(dev->fsa_dev[cid].sense_data), 3090655d722cSMark Salyzyn SCSI_SENSE_BUFFERSIZE)); 3091c4e2fbcaSRaghava Aditya Renukunta break; 3092655d722cSMark Salyzyn } 30931da177e4SLinus Torvalds case RESERVE: 30941da177e4SLinus Torvalds case RELEASE: 30951da177e4SLinus Torvalds case REZERO_UNIT: 30961da177e4SLinus Torvalds case REASSIGN_BLOCKS: 30971da177e4SLinus Torvalds case SEEK_10: 3098c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = AAC_STAT_GOOD; 3099c4e2fbcaSRaghava Aditya Renukunta break; 3100655d722cSMark Salyzyn 3101655d722cSMark Salyzyn case START_STOP: 3102655d722cSMark Salyzyn return aac_start_stop(scsicmd); 31031da177e4SLinus Torvalds 310495e852e1SSalyzyn, Mark /* FALLTHRU */ 31051da177e4SLinus Torvalds default: 31061da177e4SLinus Torvalds /* 31071da177e4SLinus Torvalds * Unhandled commands 31081da177e4SLinus Torvalds */ 3109c4e2fbcaSRaghava Aditya Renukunta dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", 3110c4e2fbcaSRaghava Aditya Renukunta scsicmd->cmnd[0])); 3111c4e2fbcaSRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 3112c4e2fbcaSRaghava Aditya Renukunta SAM_STAT_CHECK_CONDITION; 31138e31e607SSalyzyn, Mark set_sense(&dev->fsa_dev[cid].sense_data, 31141da177e4SLinus Torvalds ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, 31158e31e607SSalyzyn, Mark ASENCODE_INVALID_COMMAND, 0, 0); 31161da177e4SLinus Torvalds memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 31173ace426fSSalyzyn, Mark min_t(size_t, 31183ace426fSSalyzyn, Mark sizeof(dev->fsa_dev[cid].sense_data), 31193ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE)); 3120c4e2fbcaSRaghava Aditya Renukunta } 3121c4e2fbcaSRaghava Aditya Renukunta 3122c4e2fbcaSRaghava Aditya Renukunta scsi_done_ret: 3123c4e2fbcaSRaghava Aditya Renukunta 31241da177e4SLinus Torvalds scsicmd->scsi_done(scsicmd); 31251da177e4SLinus Torvalds return 0; 31261da177e4SLinus Torvalds } 31271da177e4SLinus Torvalds 31281da177e4SLinus Torvalds static int query_disk(struct aac_dev *dev, void __user *arg) 31291da177e4SLinus Torvalds { 31301da177e4SLinus Torvalds struct aac_query_disk qd; 31311da177e4SLinus Torvalds struct fsa_dev_info *fsa_dev_ptr; 31321da177e4SLinus Torvalds 31331da177e4SLinus Torvalds fsa_dev_ptr = dev->fsa_dev; 313490ee3466SMark Haverkamp if (!fsa_dev_ptr) 313565101355SMark Haverkamp return -EBUSY; 31361da177e4SLinus Torvalds if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) 31371da177e4SLinus Torvalds return -EFAULT; 31381da177e4SLinus Torvalds if (qd.cnum == -1) 3139e5718774SMark Haverkamp qd.cnum = qd.id; 31401da177e4SLinus Torvalds else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 31411da177e4SLinus Torvalds { 31421da177e4SLinus Torvalds if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) 31431da177e4SLinus Torvalds return -EINVAL; 31441da177e4SLinus Torvalds qd.instance = dev->scsi_host_ptr->host_no; 31451da177e4SLinus Torvalds qd.bus = 0; 31461da177e4SLinus Torvalds qd.id = CONTAINER_TO_ID(qd.cnum); 31471da177e4SLinus Torvalds qd.lun = CONTAINER_TO_LUN(qd.cnum); 31481da177e4SLinus Torvalds } 31491da177e4SLinus Torvalds else return -EINVAL; 31501da177e4SLinus Torvalds 3151fd622b1bSSalyzyn, Mark qd.valid = fsa_dev_ptr[qd.cnum].valid != 0; 31521da177e4SLinus Torvalds qd.locked = fsa_dev_ptr[qd.cnum].locked; 31531da177e4SLinus Torvalds qd.deleted = fsa_dev_ptr[qd.cnum].deleted; 31541da177e4SLinus Torvalds 31551da177e4SLinus Torvalds if (fsa_dev_ptr[qd.cnum].devname[0] == '\0') 31561da177e4SLinus Torvalds qd.unmapped = 1; 31571da177e4SLinus Torvalds else 31581da177e4SLinus Torvalds qd.unmapped = 0; 31591da177e4SLinus Torvalds 31601da177e4SLinus Torvalds strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname, 31611da177e4SLinus Torvalds min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1)); 31621da177e4SLinus Torvalds 31631da177e4SLinus Torvalds if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) 31641da177e4SLinus Torvalds return -EFAULT; 31651da177e4SLinus Torvalds return 0; 31661da177e4SLinus Torvalds } 31671da177e4SLinus Torvalds 31681da177e4SLinus Torvalds static int force_delete_disk(struct aac_dev *dev, void __user *arg) 31691da177e4SLinus Torvalds { 31701da177e4SLinus Torvalds struct aac_delete_disk dd; 31711da177e4SLinus Torvalds struct fsa_dev_info *fsa_dev_ptr; 31721da177e4SLinus Torvalds 31731da177e4SLinus Torvalds fsa_dev_ptr = dev->fsa_dev; 317465101355SMark Haverkamp if (!fsa_dev_ptr) 317565101355SMark Haverkamp return -EBUSY; 31761da177e4SLinus Torvalds 31771da177e4SLinus Torvalds if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) 31781da177e4SLinus Torvalds return -EFAULT; 31791da177e4SLinus Torvalds 31801da177e4SLinus Torvalds if (dd.cnum >= dev->maximum_num_containers) 31811da177e4SLinus Torvalds return -EINVAL; 31821da177e4SLinus Torvalds /* 31831da177e4SLinus Torvalds * Mark this container as being deleted. 31841da177e4SLinus Torvalds */ 31851da177e4SLinus Torvalds fsa_dev_ptr[dd.cnum].deleted = 1; 31861da177e4SLinus Torvalds /* 31871da177e4SLinus Torvalds * Mark the container as no longer valid 31881da177e4SLinus Torvalds */ 31891da177e4SLinus Torvalds fsa_dev_ptr[dd.cnum].valid = 0; 31901da177e4SLinus Torvalds return 0; 31911da177e4SLinus Torvalds } 31921da177e4SLinus Torvalds 31931da177e4SLinus Torvalds static int delete_disk(struct aac_dev *dev, void __user *arg) 31941da177e4SLinus Torvalds { 31951da177e4SLinus Torvalds struct aac_delete_disk dd; 31961da177e4SLinus Torvalds struct fsa_dev_info *fsa_dev_ptr; 31971da177e4SLinus Torvalds 31981da177e4SLinus Torvalds fsa_dev_ptr = dev->fsa_dev; 319990ee3466SMark Haverkamp if (!fsa_dev_ptr) 320065101355SMark Haverkamp return -EBUSY; 32011da177e4SLinus Torvalds 32021da177e4SLinus Torvalds if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) 32031da177e4SLinus Torvalds return -EFAULT; 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds if (dd.cnum >= dev->maximum_num_containers) 32061da177e4SLinus Torvalds return -EINVAL; 32071da177e4SLinus Torvalds /* 32081da177e4SLinus Torvalds * If the container is locked, it can not be deleted by the API. 32091da177e4SLinus Torvalds */ 32101da177e4SLinus Torvalds if (fsa_dev_ptr[dd.cnum].locked) 32111da177e4SLinus Torvalds return -EBUSY; 32121da177e4SLinus Torvalds else { 32131da177e4SLinus Torvalds /* 32141da177e4SLinus Torvalds * Mark the container as no longer being valid. 32151da177e4SLinus Torvalds */ 32161da177e4SLinus Torvalds fsa_dev_ptr[dd.cnum].valid = 0; 32171da177e4SLinus Torvalds fsa_dev_ptr[dd.cnum].devname[0] = '\0'; 32181da177e4SLinus Torvalds return 0; 32191da177e4SLinus Torvalds } 32201da177e4SLinus Torvalds } 32211da177e4SLinus Torvalds 32221da177e4SLinus Torvalds int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg) 32231da177e4SLinus Torvalds { 32241da177e4SLinus Torvalds switch (cmd) { 32251da177e4SLinus Torvalds case FSACTL_QUERY_DISK: 32261da177e4SLinus Torvalds return query_disk(dev, arg); 32271da177e4SLinus Torvalds case FSACTL_DELETE_DISK: 32281da177e4SLinus Torvalds return delete_disk(dev, arg); 32291da177e4SLinus Torvalds case FSACTL_FORCE_DELETE_DISK: 32301da177e4SLinus Torvalds return force_delete_disk(dev, arg); 32311da177e4SLinus Torvalds case FSACTL_GET_CONTAINERS: 32321da177e4SLinus Torvalds return aac_get_containers(dev); 32331da177e4SLinus Torvalds default: 32341da177e4SLinus Torvalds return -ENOTTY; 32351da177e4SLinus Torvalds } 32361da177e4SLinus Torvalds } 32371da177e4SLinus Torvalds 32381da177e4SLinus Torvalds /** 32391da177e4SLinus Torvalds * 32401da177e4SLinus Torvalds * aac_srb_callback 32411da177e4SLinus Torvalds * @context: the context set in the fib - here it is scsi cmd 32421da177e4SLinus Torvalds * @fibptr: pointer to the fib 32431da177e4SLinus Torvalds * 32441da177e4SLinus Torvalds * Handles the completion of a scsi command to a non dasd device 32451da177e4SLinus Torvalds * 32461da177e4SLinus Torvalds */ 32471da177e4SLinus Torvalds 32481da177e4SLinus Torvalds static void aac_srb_callback(void *context, struct fib * fibptr) 32491da177e4SLinus Torvalds { 32501da177e4SLinus Torvalds struct aac_dev *dev; 32511da177e4SLinus Torvalds struct aac_srb_reply *srbreply; 32521da177e4SLinus Torvalds struct scsi_cmnd *scsicmd; 32531da177e4SLinus Torvalds 32541da177e4SLinus Torvalds scsicmd = (struct scsi_cmnd *) context; 325503d44337SMark Haverkamp 325603d44337SMark Haverkamp if (!aac_valid_context(scsicmd, fibptr)) 325703d44337SMark Haverkamp return; 325803d44337SMark Haverkamp 3259125e1874SEric Sesterhenn BUG_ON(fibptr == NULL); 32604ec57fb4SRaghava Aditya Renukunta 32611a655040SSalyzyn, Mark dev = fibptr->dev; 32621a655040SSalyzyn, Mark 326355b87608SMahesh Rajashekhara srbreply = (struct aac_srb_reply *) fib_data(fibptr); 32644ec57fb4SRaghava Aditya Renukunta 32651da177e4SLinus Torvalds scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ 326685d22bbfSMahesh Rajashekhara 326785d22bbfSMahesh Rajashekhara if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { 326885d22bbfSMahesh Rajashekhara /* fast response */ 326985d22bbfSMahesh Rajashekhara srbreply->srb_status = cpu_to_le32(SRB_STATUS_SUCCESS); 327085d22bbfSMahesh Rajashekhara srbreply->scsi_status = cpu_to_le32(SAM_STAT_GOOD); 327185d22bbfSMahesh Rajashekhara } else { 32721da177e4SLinus Torvalds /* 32731da177e4SLinus Torvalds * Calculate resid for sg 32741da177e4SLinus Torvalds */ 3275727eead6SFUJITA Tomonori scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) 3276727eead6SFUJITA Tomonori - le32_to_cpu(srbreply->data_xfer_length)); 32774ec57fb4SRaghava Aditya Renukunta } 32784ec57fb4SRaghava Aditya Renukunta 32794ec57fb4SRaghava Aditya Renukunta 32804ec57fb4SRaghava Aditya Renukunta scsi_dma_unmap(scsicmd); 32814ec57fb4SRaghava Aditya Renukunta 32824ec57fb4SRaghava Aditya Renukunta /* expose physical device if expose_physicald flag is on */ 32834ec57fb4SRaghava Aditya Renukunta if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) 32844ec57fb4SRaghava Aditya Renukunta && expose_physicals > 0) 32854ec57fb4SRaghava Aditya Renukunta aac_expose_phy_device(scsicmd); 32864ec57fb4SRaghava Aditya Renukunta 32871da177e4SLinus Torvalds /* 32881da177e4SLinus Torvalds * First check the fib status 32891da177e4SLinus Torvalds */ 32901da177e4SLinus Torvalds 32911da177e4SLinus Torvalds if (le32_to_cpu(srbreply->status) != ST_OK) { 32921da177e4SLinus Torvalds int len; 329355b87608SMahesh Rajashekhara 32944ec57fb4SRaghava Aditya Renukunta pr_warn("aac_srb_callback: srb failed, status = %d\n", 32954ec57fb4SRaghava Aditya Renukunta le32_to_cpu(srbreply->status)); 32963ace426fSSalyzyn, Mark len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), 32973ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE); 329855b87608SMahesh Rajashekhara scsicmd->result = DID_ERROR << 16 329955b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8 330055b87608SMahesh Rajashekhara | SAM_STAT_CHECK_CONDITION; 330155b87608SMahesh Rajashekhara memcpy(scsicmd->sense_buffer, 330255b87608SMahesh Rajashekhara srbreply->sense_data, len); 33031da177e4SLinus Torvalds } 33041da177e4SLinus Torvalds 33051da177e4SLinus Torvalds /* 33061da177e4SLinus Torvalds * Next check the srb status 33071da177e4SLinus Torvalds */ 33081da177e4SLinus Torvalds switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { 33091da177e4SLinus Torvalds case SRB_STATUS_ERROR_RECOVERY: 33101da177e4SLinus Torvalds case SRB_STATUS_PENDING: 33111da177e4SLinus Torvalds case SRB_STATUS_SUCCESS: 33121da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 33131da177e4SLinus Torvalds break; 33141da177e4SLinus Torvalds case SRB_STATUS_DATA_OVERRUN: 33151da177e4SLinus Torvalds switch (scsicmd->cmnd[0]) { 33161da177e4SLinus Torvalds case READ_6: 33171da177e4SLinus Torvalds case WRITE_6: 33181da177e4SLinus Torvalds case READ_10: 33191da177e4SLinus Torvalds case WRITE_10: 33201da177e4SLinus Torvalds case READ_12: 33211da177e4SLinus Torvalds case WRITE_12: 33227a8cf29dSMark Haverkamp case READ_16: 33237a8cf29dSMark Haverkamp case WRITE_16: 332455b87608SMahesh Rajashekhara if (le32_to_cpu(srbreply->data_xfer_length) 332555b87608SMahesh Rajashekhara < scsicmd->underflow) 33264ec57fb4SRaghava Aditya Renukunta pr_warn("aacraid: SCSI CMD underflow\n"); 332755b87608SMahesh Rajashekhara else 33284ec57fb4SRaghava Aditya Renukunta pr_warn("aacraid: SCSI CMD Data Overrun\n"); 332955b87608SMahesh Rajashekhara scsicmd->result = DID_ERROR << 16 333055b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33311da177e4SLinus Torvalds break; 33324ec57fb4SRaghava Aditya Renukunta case INQUIRY: 333355b87608SMahesh Rajashekhara scsicmd->result = DID_OK << 16 333455b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33351da177e4SLinus Torvalds break; 33361da177e4SLinus Torvalds default: 33371da177e4SLinus Torvalds scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 33381da177e4SLinus Torvalds break; 33391da177e4SLinus Torvalds } 33401da177e4SLinus Torvalds break; 33411da177e4SLinus Torvalds case SRB_STATUS_ABORTED: 33421da177e4SLinus Torvalds scsicmd->result = DID_ABORT << 16 | ABORT << 8; 33431da177e4SLinus Torvalds break; 33441da177e4SLinus Torvalds case SRB_STATUS_ABORT_FAILED: 334555b87608SMahesh Rajashekhara /* 334655b87608SMahesh Rajashekhara * Not sure about this one - but assuming the 334755b87608SMahesh Rajashekhara * hba was trying to abort for some reason 334855b87608SMahesh Rajashekhara */ 33491da177e4SLinus Torvalds scsicmd->result = DID_ERROR << 16 | ABORT << 8; 33501da177e4SLinus Torvalds break; 33511da177e4SLinus Torvalds case SRB_STATUS_PARITY_ERROR: 335255b87608SMahesh Rajashekhara scsicmd->result = DID_PARITY << 16 335355b87608SMahesh Rajashekhara | MSG_PARITY_ERROR << 8; 33541da177e4SLinus Torvalds break; 33551da177e4SLinus Torvalds case SRB_STATUS_NO_DEVICE: 33561da177e4SLinus Torvalds case SRB_STATUS_INVALID_PATH_ID: 33571da177e4SLinus Torvalds case SRB_STATUS_INVALID_TARGET_ID: 33581da177e4SLinus Torvalds case SRB_STATUS_INVALID_LUN: 33591da177e4SLinus Torvalds case SRB_STATUS_SELECTION_TIMEOUT: 336055b87608SMahesh Rajashekhara scsicmd->result = DID_NO_CONNECT << 16 336155b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33621da177e4SLinus Torvalds break; 33631da177e4SLinus Torvalds 33641da177e4SLinus Torvalds case SRB_STATUS_COMMAND_TIMEOUT: 33651da177e4SLinus Torvalds case SRB_STATUS_TIMEOUT: 336655b87608SMahesh Rajashekhara scsicmd->result = DID_TIME_OUT << 16 336755b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33681da177e4SLinus Torvalds break; 33691da177e4SLinus Torvalds 33701da177e4SLinus Torvalds case SRB_STATUS_BUSY: 337155b87608SMahesh Rajashekhara scsicmd->result = DID_BUS_BUSY << 16 337255b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33731da177e4SLinus Torvalds break; 33741da177e4SLinus Torvalds 33751da177e4SLinus Torvalds case SRB_STATUS_BUS_RESET: 337655b87608SMahesh Rajashekhara scsicmd->result = DID_RESET << 16 337755b87608SMahesh Rajashekhara | COMMAND_COMPLETE << 8; 33781da177e4SLinus Torvalds break; 33791da177e4SLinus Torvalds 33801da177e4SLinus Torvalds case SRB_STATUS_MESSAGE_REJECTED: 338155b87608SMahesh Rajashekhara scsicmd->result = DID_ERROR << 16 338255b87608SMahesh Rajashekhara | MESSAGE_REJECT << 8; 33831da177e4SLinus Torvalds break; 33841da177e4SLinus Torvalds case SRB_STATUS_REQUEST_FLUSHED: 33851da177e4SLinus Torvalds case SRB_STATUS_ERROR: 33861da177e4SLinus Torvalds case SRB_STATUS_INVALID_REQUEST: 33871da177e4SLinus Torvalds case SRB_STATUS_REQUEST_SENSE_FAILED: 33881da177e4SLinus Torvalds case SRB_STATUS_NO_HBA: 33891da177e4SLinus Torvalds case SRB_STATUS_UNEXPECTED_BUS_FREE: 33901da177e4SLinus Torvalds case SRB_STATUS_PHASE_SEQUENCE_FAILURE: 33911da177e4SLinus Torvalds case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: 33921da177e4SLinus Torvalds case SRB_STATUS_DELAYED_RETRY: 33931da177e4SLinus Torvalds case SRB_STATUS_BAD_FUNCTION: 33941da177e4SLinus Torvalds case SRB_STATUS_NOT_STARTED: 33951da177e4SLinus Torvalds case SRB_STATUS_NOT_IN_USE: 33961da177e4SLinus Torvalds case SRB_STATUS_FORCE_ABORT: 33971da177e4SLinus Torvalds case SRB_STATUS_DOMAIN_VALIDATION_FAIL: 33981da177e4SLinus Torvalds default: 33991da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO 34004ec57fb4SRaghava Aditya Renukunta pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n", 34011da177e4SLinus Torvalds le32_to_cpu(srbreply->srb_status) & 0x3F, 34021da177e4SLinus Torvalds aac_get_status_string( 34031da177e4SLinus Torvalds le32_to_cpu(srbreply->srb_status) & 0x3F), 34041da177e4SLinus Torvalds scsicmd->cmnd[0], 34051da177e4SLinus Torvalds le32_to_cpu(srbreply->scsi_status)); 34061da177e4SLinus Torvalds #endif 34074ec57fb4SRaghava Aditya Renukunta /* 34084ec57fb4SRaghava Aditya Renukunta * When the CC bit is SET by the host in ATA pass thru CDB, 34094ec57fb4SRaghava Aditya Renukunta * driver is supposed to return DID_OK 34104ec57fb4SRaghava Aditya Renukunta * 34114ec57fb4SRaghava Aditya Renukunta * When the CC bit is RESET by the host, driver should 34124ec57fb4SRaghava Aditya Renukunta * return DID_ERROR 34134ec57fb4SRaghava Aditya Renukunta */ 34141fc8010aSRajashekhara, Mahesh if ((scsicmd->cmnd[0] == ATA_12) 34151fc8010aSRajashekhara, Mahesh || (scsicmd->cmnd[0] == ATA_16)) { 34164ec57fb4SRaghava Aditya Renukunta 34171fc8010aSRajashekhara, Mahesh if (scsicmd->cmnd[2] & (0x01 << 5)) { 34181fc8010aSRajashekhara, Mahesh scsicmd->result = DID_OK << 16 34191fc8010aSRajashekhara, Mahesh | COMMAND_COMPLETE << 8; 34201da177e4SLinus Torvalds break; 34211fc8010aSRajashekhara, Mahesh } else { 34221fc8010aSRajashekhara, Mahesh scsicmd->result = DID_ERROR << 16 34231fc8010aSRajashekhara, Mahesh | COMMAND_COMPLETE << 8; 34241fc8010aSRajashekhara, Mahesh break; 34251fc8010aSRajashekhara, Mahesh } 34261fc8010aSRajashekhara, Mahesh } else { 34271fc8010aSRajashekhara, Mahesh scsicmd->result = DID_ERROR << 16 34281fc8010aSRajashekhara, Mahesh | COMMAND_COMPLETE << 8; 34291fc8010aSRajashekhara, Mahesh break; 34301fc8010aSRajashekhara, Mahesh } 34311da177e4SLinus Torvalds } 343255b87608SMahesh Rajashekhara if (le32_to_cpu(srbreply->scsi_status) 343355b87608SMahesh Rajashekhara == SAM_STAT_CHECK_CONDITION) { 34341da177e4SLinus Torvalds int len; 343555b87608SMahesh Rajashekhara 34361da177e4SLinus Torvalds scsicmd->result |= SAM_STAT_CHECK_CONDITION; 34373ace426fSSalyzyn, Mark len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), 34383ace426fSSalyzyn, Mark SCSI_SENSE_BUFFERSIZE); 34391da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO 34404ec57fb4SRaghava Aditya Renukunta pr_warn("aac_srb_callback: check condition, status = %d len=%d\n", 34417a8cf29dSMark Haverkamp le32_to_cpu(srbreply->status), len); 34421da177e4SLinus Torvalds #endif 344355b87608SMahesh Rajashekhara memcpy(scsicmd->sense_buffer, 344455b87608SMahesh Rajashekhara srbreply->sense_data, len); 344555b87608SMahesh Rajashekhara } 34464ec57fb4SRaghava Aditya Renukunta 34471da177e4SLinus Torvalds /* 34481da177e4SLinus Torvalds * OR in the scsi status (already shifted up a bit) 34491da177e4SLinus Torvalds */ 34501da177e4SLinus Torvalds scsicmd->result |= le32_to_cpu(srbreply->scsi_status); 34511da177e4SLinus Torvalds 3452bfb35aa8SMark Haverkamp aac_fib_complete(fibptr); 34538e0c5ebdSMark Haverkamp scsicmd->scsi_done(scsicmd); 34541da177e4SLinus Torvalds } 34551da177e4SLinus Torvalds 3456ab5d129fSRaghava Aditya Renukunta static void hba_resp_task_complete(struct aac_dev *dev, 3457ab5d129fSRaghava Aditya Renukunta struct scsi_cmnd *scsicmd, 3458ab5d129fSRaghava Aditya Renukunta struct aac_hba_resp *err) { 3459ab5d129fSRaghava Aditya Renukunta 3460ab5d129fSRaghava Aditya Renukunta scsicmd->result = err->status; 3461ab5d129fSRaghava Aditya Renukunta /* set residual count */ 3462ab5d129fSRaghava Aditya Renukunta scsi_set_resid(scsicmd, le32_to_cpu(err->residual_count)); 3463ab5d129fSRaghava Aditya Renukunta 3464ab5d129fSRaghava Aditya Renukunta switch (err->status) { 3465ab5d129fSRaghava Aditya Renukunta case SAM_STAT_GOOD: 3466ab5d129fSRaghava Aditya Renukunta scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; 3467ab5d129fSRaghava Aditya Renukunta break; 3468ab5d129fSRaghava Aditya Renukunta case SAM_STAT_CHECK_CONDITION: 3469ab5d129fSRaghava Aditya Renukunta { 3470ab5d129fSRaghava Aditya Renukunta int len; 3471ab5d129fSRaghava Aditya Renukunta 3472ab5d129fSRaghava Aditya Renukunta len = min_t(u8, err->sense_response_data_len, 3473ab5d129fSRaghava Aditya Renukunta SCSI_SENSE_BUFFERSIZE); 3474ab5d129fSRaghava Aditya Renukunta if (len) 3475ab5d129fSRaghava Aditya Renukunta memcpy(scsicmd->sense_buffer, 3476ab5d129fSRaghava Aditya Renukunta err->sense_response_buf, len); 3477ab5d129fSRaghava Aditya Renukunta scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; 3478ab5d129fSRaghava Aditya Renukunta break; 3479ab5d129fSRaghava Aditya Renukunta } 3480ab5d129fSRaghava Aditya Renukunta case SAM_STAT_BUSY: 3481ab5d129fSRaghava Aditya Renukunta scsicmd->result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; 3482ab5d129fSRaghava Aditya Renukunta break; 3483ab5d129fSRaghava Aditya Renukunta case SAM_STAT_TASK_ABORTED: 3484ab5d129fSRaghava Aditya Renukunta scsicmd->result |= DID_ABORT << 16 | ABORT << 8; 3485ab5d129fSRaghava Aditya Renukunta break; 3486ab5d129fSRaghava Aditya Renukunta case SAM_STAT_RESERVATION_CONFLICT: 3487ab5d129fSRaghava Aditya Renukunta case SAM_STAT_TASK_SET_FULL: 3488ab5d129fSRaghava Aditya Renukunta default: 3489ab5d129fSRaghava Aditya Renukunta scsicmd->result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8; 3490ab5d129fSRaghava Aditya Renukunta break; 3491ab5d129fSRaghava Aditya Renukunta } 3492ab5d129fSRaghava Aditya Renukunta } 3493ab5d129fSRaghava Aditya Renukunta 3494ab5d129fSRaghava Aditya Renukunta static void hba_resp_task_failure(struct aac_dev *dev, 3495ab5d129fSRaghava Aditya Renukunta struct scsi_cmnd *scsicmd, 3496ab5d129fSRaghava Aditya Renukunta struct aac_hba_resp *err) 3497ab5d129fSRaghava Aditya Renukunta { 3498ab5d129fSRaghava Aditya Renukunta switch (err->status) { 3499ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_HBAMODE_DISABLED: 3500ab5d129fSRaghava Aditya Renukunta { 3501ab5d129fSRaghava Aditya Renukunta u32 bus, cid; 3502ab5d129fSRaghava Aditya Renukunta 3503ab5d129fSRaghava Aditya Renukunta bus = aac_logical_to_phys(scmd_channel(scsicmd)); 3504ab5d129fSRaghava Aditya Renukunta cid = scmd_id(scsicmd); 3505ab5d129fSRaghava Aditya Renukunta if (dev->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { 3506ab5d129fSRaghava Aditya Renukunta dev->hba_map[bus][cid].devtype = AAC_DEVTYPE_ARC_RAW; 3507ab5d129fSRaghava Aditya Renukunta dev->hba_map[bus][cid].rmw_nexus = 0xffffffff; 3508ab5d129fSRaghava Aditya Renukunta } 3509ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 3510ab5d129fSRaghava Aditya Renukunta break; 3511ab5d129fSRaghava Aditya Renukunta } 3512ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_IO_ERROR: 3513ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_NO_PATH_TO_DEVICE: 3514ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | 3515ab5d129fSRaghava Aditya Renukunta COMMAND_COMPLETE << 8 | SAM_STAT_BUSY; 3516ab5d129fSRaghava Aditya Renukunta break; 3517ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_IO_ABORTED: 3518ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_ABORT << 16 | ABORT << 8; 3519ab5d129fSRaghava Aditya Renukunta break; 3520ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_INVALID_DEVICE: 3521ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 3522ab5d129fSRaghava Aditya Renukunta break; 3523ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_UNDERRUN: 3524ab5d129fSRaghava Aditya Renukunta /* UNDERRUN is OK */ 3525ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 3526ab5d129fSRaghava Aditya Renukunta break; 3527ab5d129fSRaghava Aditya Renukunta case HBA_RESP_STAT_OVERRUN: 3528ab5d129fSRaghava Aditya Renukunta default: 3529ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; 3530ab5d129fSRaghava Aditya Renukunta break; 3531ab5d129fSRaghava Aditya Renukunta } 3532ab5d129fSRaghava Aditya Renukunta } 3533ab5d129fSRaghava Aditya Renukunta 35341da177e4SLinus Torvalds /** 35351da177e4SLinus Torvalds * 3536ab5d129fSRaghava Aditya Renukunta * aac_hba_callback 3537ab5d129fSRaghava Aditya Renukunta * @context: the context set in the fib - here it is scsi cmd 3538ab5d129fSRaghava Aditya Renukunta * @fibptr: pointer to the fib 3539ab5d129fSRaghava Aditya Renukunta * 3540ab5d129fSRaghava Aditya Renukunta * Handles the completion of a native HBA scsi command 3541ab5d129fSRaghava Aditya Renukunta * 3542ab5d129fSRaghava Aditya Renukunta */ 3543ab5d129fSRaghava Aditya Renukunta void aac_hba_callback(void *context, struct fib *fibptr) 3544ab5d129fSRaghava Aditya Renukunta { 3545ab5d129fSRaghava Aditya Renukunta struct aac_dev *dev; 3546ab5d129fSRaghava Aditya Renukunta struct scsi_cmnd *scsicmd; 3547ab5d129fSRaghava Aditya Renukunta 3548ab5d129fSRaghava Aditya Renukunta struct aac_hba_resp *err = 3549ab5d129fSRaghava Aditya Renukunta &((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err; 3550ab5d129fSRaghava Aditya Renukunta 3551ab5d129fSRaghava Aditya Renukunta scsicmd = (struct scsi_cmnd *) context; 3552ab5d129fSRaghava Aditya Renukunta 3553ab5d129fSRaghava Aditya Renukunta if (!aac_valid_context(scsicmd, fibptr)) 3554ab5d129fSRaghava Aditya Renukunta return; 3555ab5d129fSRaghava Aditya Renukunta 3556ab5d129fSRaghava Aditya Renukunta WARN_ON(fibptr == NULL); 3557ab5d129fSRaghava Aditya Renukunta dev = fibptr->dev; 3558ab5d129fSRaghava Aditya Renukunta 3559ab5d129fSRaghava Aditya Renukunta if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF)) 3560ab5d129fSRaghava Aditya Renukunta scsi_dma_unmap(scsicmd); 3561ab5d129fSRaghava Aditya Renukunta 3562ab5d129fSRaghava Aditya Renukunta if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { 3563ab5d129fSRaghava Aditya Renukunta /* fast response */ 3564ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 3565ab5d129fSRaghava Aditya Renukunta goto out; 3566ab5d129fSRaghava Aditya Renukunta } 3567ab5d129fSRaghava Aditya Renukunta 3568ab5d129fSRaghava Aditya Renukunta switch (err->service_response) { 3569ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_TASK_COMPLETE: 3570ab5d129fSRaghava Aditya Renukunta hba_resp_task_complete(dev, scsicmd, err); 3571ab5d129fSRaghava Aditya Renukunta break; 3572ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_FAILURE: 3573ab5d129fSRaghava Aditya Renukunta hba_resp_task_failure(dev, scsicmd, err); 3574ab5d129fSRaghava Aditya Renukunta break; 3575ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_TMF_REJECTED: 3576ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; 3577ab5d129fSRaghava Aditya Renukunta break; 3578ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_TMF_LUN_INVALID: 3579ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 3580ab5d129fSRaghava Aditya Renukunta break; 3581ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_TMF_COMPLETE: 3582ab5d129fSRaghava Aditya Renukunta case HBA_RESP_SVCRES_TMF_SUCCEEDED: 3583ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 3584ab5d129fSRaghava Aditya Renukunta break; 3585ab5d129fSRaghava Aditya Renukunta default: 3586ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; 3587ab5d129fSRaghava Aditya Renukunta break; 3588ab5d129fSRaghava Aditya Renukunta } 3589ab5d129fSRaghava Aditya Renukunta 3590ab5d129fSRaghava Aditya Renukunta out: 3591ab5d129fSRaghava Aditya Renukunta aac_fib_complete(fibptr); 3592ab5d129fSRaghava Aditya Renukunta 3593ab5d129fSRaghava Aditya Renukunta if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) 3594ab5d129fSRaghava Aditya Renukunta scsicmd->SCp.sent_command = 1; 3595ab5d129fSRaghava Aditya Renukunta else 3596ab5d129fSRaghava Aditya Renukunta scsicmd->scsi_done(scsicmd); 3597ab5d129fSRaghava Aditya Renukunta } 3598ab5d129fSRaghava Aditya Renukunta 3599ab5d129fSRaghava Aditya Renukunta /** 3600ab5d129fSRaghava Aditya Renukunta * 3601ab5d129fSRaghava Aditya Renukunta * aac_send_srb_fib 36021da177e4SLinus Torvalds * @scsicmd: the scsi command block 36031da177e4SLinus Torvalds * 36041da177e4SLinus Torvalds * This routine will form a FIB and fill in the aac_srb from the 36051da177e4SLinus Torvalds * scsicmd passed in. 36061da177e4SLinus Torvalds */ 36071da177e4SLinus Torvalds 36081da177e4SLinus Torvalds static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) 36091da177e4SLinus Torvalds { 36101da177e4SLinus Torvalds struct fib* cmd_fibcontext; 36111da177e4SLinus Torvalds struct aac_dev* dev; 36121da177e4SLinus Torvalds int status; 36131da177e4SLinus Torvalds 361484971738SMark Haverkamp dev = (struct aac_dev *)scsicmd->device->host->hostdata; 3615e5718774SMark Haverkamp if (scmd_id(scsicmd) >= dev->maximum_num_physicals || 361684971738SMark Haverkamp scsicmd->device->lun > 7) { 36171da177e4SLinus Torvalds scsicmd->result = DID_NO_CONNECT << 16; 36181da177e4SLinus Torvalds scsicmd->scsi_done(scsicmd); 36191da177e4SLinus Torvalds return 0; 36201da177e4SLinus Torvalds } 36211da177e4SLinus Torvalds 36221da177e4SLinus Torvalds /* 36231da177e4SLinus Torvalds * Allocate and initialize a Fib then setup a BlockWrite command 36241da177e4SLinus Torvalds */ 36256bf3b630SRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 36266bf3b630SRaghava Aditya Renukunta 3627e8f32de5SMark Haverkamp status = aac_adapter_scsi(cmd_fibcontext, scsicmd); 36281da177e4SLinus Torvalds 36291da177e4SLinus Torvalds /* 36301da177e4SLinus Torvalds * Check that the command queued to the controller 36311da177e4SLinus Torvalds */ 36321da177e4SLinus Torvalds if (status == -EINPROGRESS) { 363377d644d4SMark Haverkamp scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 36341da177e4SLinus Torvalds return 0; 36351da177e4SLinus Torvalds } 36361da177e4SLinus Torvalds 3637bfb35aa8SMark Haverkamp printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status); 3638bfb35aa8SMark Haverkamp aac_fib_complete(cmd_fibcontext); 3639bfb35aa8SMark Haverkamp aac_fib_free(cmd_fibcontext); 36401da177e4SLinus Torvalds 36411da177e4SLinus Torvalds return -1; 36421da177e4SLinus Torvalds } 36431da177e4SLinus Torvalds 3644ab5d129fSRaghava Aditya Renukunta /** 3645ab5d129fSRaghava Aditya Renukunta * 3646ab5d129fSRaghava Aditya Renukunta * aac_send_hba_fib 3647ab5d129fSRaghava Aditya Renukunta * @scsicmd: the scsi command block 3648ab5d129fSRaghava Aditya Renukunta * 3649ab5d129fSRaghava Aditya Renukunta * This routine will form a FIB and fill in the aac_hba_cmd_req from the 3650ab5d129fSRaghava Aditya Renukunta * scsicmd passed in. 3651ab5d129fSRaghava Aditya Renukunta */ 3652ab5d129fSRaghava Aditya Renukunta static int aac_send_hba_fib(struct scsi_cmnd *scsicmd) 3653ab5d129fSRaghava Aditya Renukunta { 3654ab5d129fSRaghava Aditya Renukunta struct fib *cmd_fibcontext; 3655ab5d129fSRaghava Aditya Renukunta struct aac_dev *dev; 3656ab5d129fSRaghava Aditya Renukunta int status; 3657ab5d129fSRaghava Aditya Renukunta 3658ab5d129fSRaghava Aditya Renukunta dev = shost_priv(scsicmd->device->host); 3659ab5d129fSRaghava Aditya Renukunta if (scmd_id(scsicmd) >= dev->maximum_num_physicals || 3660ab5d129fSRaghava Aditya Renukunta scsicmd->device->lun > AAC_MAX_LUN - 1) { 3661ab5d129fSRaghava Aditya Renukunta scsicmd->result = DID_NO_CONNECT << 16; 3662ab5d129fSRaghava Aditya Renukunta scsicmd->scsi_done(scsicmd); 3663ab5d129fSRaghava Aditya Renukunta return 0; 3664ab5d129fSRaghava Aditya Renukunta } 3665ab5d129fSRaghava Aditya Renukunta 3666ab5d129fSRaghava Aditya Renukunta /* 3667ab5d129fSRaghava Aditya Renukunta * Allocate and initialize a Fib then setup a BlockWrite command 3668ab5d129fSRaghava Aditya Renukunta */ 3669ab5d129fSRaghava Aditya Renukunta cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 3670ab5d129fSRaghava Aditya Renukunta if (!cmd_fibcontext) 3671ab5d129fSRaghava Aditya Renukunta return -1; 3672ab5d129fSRaghava Aditya Renukunta 3673ab5d129fSRaghava Aditya Renukunta status = aac_adapter_hba(cmd_fibcontext, scsicmd); 3674ab5d129fSRaghava Aditya Renukunta 3675ab5d129fSRaghava Aditya Renukunta /* 3676ab5d129fSRaghava Aditya Renukunta * Check that the command queued to the controller 3677ab5d129fSRaghava Aditya Renukunta */ 3678ab5d129fSRaghava Aditya Renukunta if (status == -EINPROGRESS) { 3679ab5d129fSRaghava Aditya Renukunta scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 3680ab5d129fSRaghava Aditya Renukunta return 0; 3681ab5d129fSRaghava Aditya Renukunta } 3682ab5d129fSRaghava Aditya Renukunta 3683ab5d129fSRaghava Aditya Renukunta pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n", 3684ab5d129fSRaghava Aditya Renukunta status); 3685ab5d129fSRaghava Aditya Renukunta aac_fib_complete(cmd_fibcontext); 3686ab5d129fSRaghava Aditya Renukunta aac_fib_free(cmd_fibcontext); 3687ab5d129fSRaghava Aditya Renukunta 3688ab5d129fSRaghava Aditya Renukunta return -1; 3689ab5d129fSRaghava Aditya Renukunta } 3690ab5d129fSRaghava Aditya Renukunta 3691ab5d129fSRaghava Aditya Renukunta 36920b433447SMahesh Rajashekhara static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) 36931da177e4SLinus Torvalds { 36941da177e4SLinus Torvalds struct aac_dev *dev; 36951da177e4SLinus Torvalds unsigned long byte_count = 0; 3696727eead6SFUJITA Tomonori int nseg; 36971da177e4SLinus Torvalds 36981da177e4SLinus Torvalds dev = (struct aac_dev *)scsicmd->device->host->hostdata; 36991da177e4SLinus Torvalds // Get rid of old data 37001da177e4SLinus Torvalds psg->count = 0; 37011da177e4SLinus Torvalds psg->sg[0].addr = 0; 37021da177e4SLinus Torvalds psg->sg[0].count = 0; 3703727eead6SFUJITA Tomonori 3704727eead6SFUJITA Tomonori nseg = scsi_dma_map(scsicmd); 37050b433447SMahesh Rajashekhara if (nseg < 0) 37060b433447SMahesh Rajashekhara return nseg; 3707727eead6SFUJITA Tomonori if (nseg) { 37081da177e4SLinus Torvalds struct scatterlist *sg; 37091da177e4SLinus Torvalds int i; 37101da177e4SLinus Torvalds 3711727eead6SFUJITA Tomonori psg->count = cpu_to_le32(nseg); 37121da177e4SLinus Torvalds 3713727eead6SFUJITA Tomonori scsi_for_each_sg(scsicmd, sg, nseg, i) { 37141da177e4SLinus Torvalds psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); 37151da177e4SLinus Torvalds psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); 37161da177e4SLinus Torvalds byte_count += sg_dma_len(sg); 37171da177e4SLinus Torvalds } 37181da177e4SLinus Torvalds /* hba wants the size to be exact */ 3719727eead6SFUJITA Tomonori if (byte_count > scsi_bufflen(scsicmd)) { 372056b58712SMark Haverkamp u32 temp = le32_to_cpu(psg->sg[i-1].count) - 3721727eead6SFUJITA Tomonori (byte_count - scsi_bufflen(scsicmd)); 372256b58712SMark Haverkamp psg->sg[i-1].count = cpu_to_le32(temp); 3723727eead6SFUJITA Tomonori byte_count = scsi_bufflen(scsicmd); 37241da177e4SLinus Torvalds } 37251da177e4SLinus Torvalds /* Check for command underflow */ 37261da177e4SLinus Torvalds if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ 37271da177e4SLinus Torvalds printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 37281da177e4SLinus Torvalds byte_count, scsicmd->underflow); 37291da177e4SLinus Torvalds } 37301da177e4SLinus Torvalds } 37311da177e4SLinus Torvalds return byte_count; 37321da177e4SLinus Torvalds } 37331da177e4SLinus Torvalds 37341da177e4SLinus Torvalds 37350b433447SMahesh Rajashekhara static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg) 37361da177e4SLinus Torvalds { 37371da177e4SLinus Torvalds struct aac_dev *dev; 37381da177e4SLinus Torvalds unsigned long byte_count = 0; 373956b58712SMark Haverkamp u64 addr; 3740727eead6SFUJITA Tomonori int nseg; 37411da177e4SLinus Torvalds 37421da177e4SLinus Torvalds dev = (struct aac_dev *)scsicmd->device->host->hostdata; 37431da177e4SLinus Torvalds // Get rid of old data 37441da177e4SLinus Torvalds psg->count = 0; 37451da177e4SLinus Torvalds psg->sg[0].addr[0] = 0; 37461da177e4SLinus Torvalds psg->sg[0].addr[1] = 0; 37471da177e4SLinus Torvalds psg->sg[0].count = 0; 3748727eead6SFUJITA Tomonori 3749727eead6SFUJITA Tomonori nseg = scsi_dma_map(scsicmd); 37500b433447SMahesh Rajashekhara if (nseg < 0) 37510b433447SMahesh Rajashekhara return nseg; 3752727eead6SFUJITA Tomonori if (nseg) { 37531da177e4SLinus Torvalds struct scatterlist *sg; 37541da177e4SLinus Torvalds int i; 37551da177e4SLinus Torvalds 3756727eead6SFUJITA Tomonori scsi_for_each_sg(scsicmd, sg, nseg, i) { 37571241f359SMark Haverkamp int count = sg_dma_len(sg); 375856b58712SMark Haverkamp addr = sg_dma_address(sg); 375956b58712SMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 376056b58712SMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 37611241f359SMark Haverkamp psg->sg[i].count = cpu_to_le32(count); 37621241f359SMark Haverkamp byte_count += count; 37631da177e4SLinus Torvalds } 3764727eead6SFUJITA Tomonori psg->count = cpu_to_le32(nseg); 37651da177e4SLinus Torvalds /* hba wants the size to be exact */ 3766727eead6SFUJITA Tomonori if (byte_count > scsi_bufflen(scsicmd)) { 376756b58712SMark Haverkamp u32 temp = le32_to_cpu(psg->sg[i-1].count) - 3768727eead6SFUJITA Tomonori (byte_count - scsi_bufflen(scsicmd)); 376956b58712SMark Haverkamp psg->sg[i-1].count = cpu_to_le32(temp); 3770727eead6SFUJITA Tomonori byte_count = scsi_bufflen(scsicmd); 37711da177e4SLinus Torvalds } 37721da177e4SLinus Torvalds /* Check for command underflow */ 37731da177e4SLinus Torvalds if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ 37741da177e4SLinus Torvalds printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 37751da177e4SLinus Torvalds byte_count, scsicmd->underflow); 37761da177e4SLinus Torvalds } 37771da177e4SLinus Torvalds } 37781da177e4SLinus Torvalds return byte_count; 37791da177e4SLinus Torvalds } 37801da177e4SLinus Torvalds 37810b433447SMahesh Rajashekhara static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg) 37820e68c003SMark Haverkamp { 37830e68c003SMark Haverkamp unsigned long byte_count = 0; 3784727eead6SFUJITA Tomonori int nseg; 37850e68c003SMark Haverkamp 37860e68c003SMark Haverkamp // Get rid of old data 37870e68c003SMark Haverkamp psg->count = 0; 37880e68c003SMark Haverkamp psg->sg[0].next = 0; 37890e68c003SMark Haverkamp psg->sg[0].prev = 0; 37900e68c003SMark Haverkamp psg->sg[0].addr[0] = 0; 37910e68c003SMark Haverkamp psg->sg[0].addr[1] = 0; 37920e68c003SMark Haverkamp psg->sg[0].count = 0; 37930e68c003SMark Haverkamp psg->sg[0].flags = 0; 3794727eead6SFUJITA Tomonori 3795727eead6SFUJITA Tomonori nseg = scsi_dma_map(scsicmd); 37960b433447SMahesh Rajashekhara if (nseg < 0) 37970b433447SMahesh Rajashekhara return nseg; 3798727eead6SFUJITA Tomonori if (nseg) { 37990e68c003SMark Haverkamp struct scatterlist *sg; 38000e68c003SMark Haverkamp int i; 38010e68c003SMark Haverkamp 3802727eead6SFUJITA Tomonori scsi_for_each_sg(scsicmd, sg, nseg, i) { 38030e68c003SMark Haverkamp int count = sg_dma_len(sg); 38040e68c003SMark Haverkamp u64 addr = sg_dma_address(sg); 38050e68c003SMark Haverkamp psg->sg[i].next = 0; 38060e68c003SMark Haverkamp psg->sg[i].prev = 0; 38070e68c003SMark Haverkamp psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); 38080e68c003SMark Haverkamp psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); 38090e68c003SMark Haverkamp psg->sg[i].count = cpu_to_le32(count); 38100e68c003SMark Haverkamp psg->sg[i].flags = 0; 38110e68c003SMark Haverkamp byte_count += count; 38120e68c003SMark Haverkamp } 3813727eead6SFUJITA Tomonori psg->count = cpu_to_le32(nseg); 38140e68c003SMark Haverkamp /* hba wants the size to be exact */ 3815727eead6SFUJITA Tomonori if (byte_count > scsi_bufflen(scsicmd)) { 38160e68c003SMark Haverkamp u32 temp = le32_to_cpu(psg->sg[i-1].count) - 3817727eead6SFUJITA Tomonori (byte_count - scsi_bufflen(scsicmd)); 38180e68c003SMark Haverkamp psg->sg[i-1].count = cpu_to_le32(temp); 3819727eead6SFUJITA Tomonori byte_count = scsi_bufflen(scsicmd); 38200e68c003SMark Haverkamp } 38210e68c003SMark Haverkamp /* Check for command underflow */ 38220e68c003SMark Haverkamp if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ 38230e68c003SMark Haverkamp printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 38240e68c003SMark Haverkamp byte_count, scsicmd->underflow); 38250e68c003SMark Haverkamp } 38260e68c003SMark Haverkamp } 38270e68c003SMark Haverkamp return byte_count; 38280e68c003SMark Haverkamp } 38290e68c003SMark Haverkamp 38300b433447SMahesh Rajashekhara static long aac_build_sgraw2(struct scsi_cmnd *scsicmd, 38310b433447SMahesh Rajashekhara struct aac_raw_io2 *rio2, int sg_max) 383285d22bbfSMahesh Rajashekhara { 383385d22bbfSMahesh Rajashekhara unsigned long byte_count = 0; 383485d22bbfSMahesh Rajashekhara int nseg; 383585d22bbfSMahesh Rajashekhara 383685d22bbfSMahesh Rajashekhara nseg = scsi_dma_map(scsicmd); 38370b433447SMahesh Rajashekhara if (nseg < 0) 38380b433447SMahesh Rajashekhara return nseg; 383985d22bbfSMahesh Rajashekhara if (nseg) { 384085d22bbfSMahesh Rajashekhara struct scatterlist *sg; 384185d22bbfSMahesh Rajashekhara int i, conformable = 0; 384285d22bbfSMahesh Rajashekhara u32 min_size = PAGE_SIZE, cur_size; 384385d22bbfSMahesh Rajashekhara 384485d22bbfSMahesh Rajashekhara scsi_for_each_sg(scsicmd, sg, nseg, i) { 384585d22bbfSMahesh Rajashekhara int count = sg_dma_len(sg); 384685d22bbfSMahesh Rajashekhara u64 addr = sg_dma_address(sg); 384785d22bbfSMahesh Rajashekhara 384885d22bbfSMahesh Rajashekhara BUG_ON(i >= sg_max); 384985d22bbfSMahesh Rajashekhara rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32)); 385085d22bbfSMahesh Rajashekhara rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff)); 385185d22bbfSMahesh Rajashekhara cur_size = cpu_to_le32(count); 385285d22bbfSMahesh Rajashekhara rio2->sge[i].length = cur_size; 385385d22bbfSMahesh Rajashekhara rio2->sge[i].flags = 0; 385485d22bbfSMahesh Rajashekhara if (i == 0) { 385585d22bbfSMahesh Rajashekhara conformable = 1; 385685d22bbfSMahesh Rajashekhara rio2->sgeFirstSize = cur_size; 385785d22bbfSMahesh Rajashekhara } else if (i == 1) { 385885d22bbfSMahesh Rajashekhara rio2->sgeNominalSize = cur_size; 385985d22bbfSMahesh Rajashekhara min_size = cur_size; 386085d22bbfSMahesh Rajashekhara } else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) { 386185d22bbfSMahesh Rajashekhara conformable = 0; 386285d22bbfSMahesh Rajashekhara if (cur_size < min_size) 386385d22bbfSMahesh Rajashekhara min_size = cur_size; 386485d22bbfSMahesh Rajashekhara } 386585d22bbfSMahesh Rajashekhara byte_count += count; 386685d22bbfSMahesh Rajashekhara } 386785d22bbfSMahesh Rajashekhara 386885d22bbfSMahesh Rajashekhara /* hba wants the size to be exact */ 386985d22bbfSMahesh Rajashekhara if (byte_count > scsi_bufflen(scsicmd)) { 387085d22bbfSMahesh Rajashekhara u32 temp = le32_to_cpu(rio2->sge[i-1].length) - 387185d22bbfSMahesh Rajashekhara (byte_count - scsi_bufflen(scsicmd)); 387285d22bbfSMahesh Rajashekhara rio2->sge[i-1].length = cpu_to_le32(temp); 387385d22bbfSMahesh Rajashekhara byte_count = scsi_bufflen(scsicmd); 387485d22bbfSMahesh Rajashekhara } 387585d22bbfSMahesh Rajashekhara 387685d22bbfSMahesh Rajashekhara rio2->sgeCnt = cpu_to_le32(nseg); 387785d22bbfSMahesh Rajashekhara rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212); 387885d22bbfSMahesh Rajashekhara /* not conformable: evaluate required sg elements */ 387985d22bbfSMahesh Rajashekhara if (!conformable) { 388085d22bbfSMahesh Rajashekhara int j, nseg_new = nseg, err_found; 388185d22bbfSMahesh Rajashekhara for (i = min_size / PAGE_SIZE; i >= 1; --i) { 388285d22bbfSMahesh Rajashekhara err_found = 0; 388385d22bbfSMahesh Rajashekhara nseg_new = 2; 388485d22bbfSMahesh Rajashekhara for (j = 1; j < nseg - 1; ++j) { 388585d22bbfSMahesh Rajashekhara if (rio2->sge[j].length % (i*PAGE_SIZE)) { 388685d22bbfSMahesh Rajashekhara err_found = 1; 388785d22bbfSMahesh Rajashekhara break; 388885d22bbfSMahesh Rajashekhara } 388985d22bbfSMahesh Rajashekhara nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE)); 389085d22bbfSMahesh Rajashekhara } 389185d22bbfSMahesh Rajashekhara if (!err_found) 389285d22bbfSMahesh Rajashekhara break; 389385d22bbfSMahesh Rajashekhara } 389485d22bbfSMahesh Rajashekhara if (i > 0 && nseg_new <= sg_max) 389585d22bbfSMahesh Rajashekhara aac_convert_sgraw2(rio2, i, nseg, nseg_new); 389685d22bbfSMahesh Rajashekhara } else 389785d22bbfSMahesh Rajashekhara rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); 389885d22bbfSMahesh Rajashekhara 389985d22bbfSMahesh Rajashekhara /* Check for command underflow */ 390085d22bbfSMahesh Rajashekhara if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 390185d22bbfSMahesh Rajashekhara printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 390285d22bbfSMahesh Rajashekhara byte_count, scsicmd->underflow); 390385d22bbfSMahesh Rajashekhara } 390485d22bbfSMahesh Rajashekhara } 390585d22bbfSMahesh Rajashekhara 390685d22bbfSMahesh Rajashekhara return byte_count; 390785d22bbfSMahesh Rajashekhara } 390885d22bbfSMahesh Rajashekhara 390985d22bbfSMahesh Rajashekhara static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new) 391085d22bbfSMahesh Rajashekhara { 391185d22bbfSMahesh Rajashekhara struct sge_ieee1212 *sge; 391285d22bbfSMahesh Rajashekhara int i, j, pos; 391385d22bbfSMahesh Rajashekhara u32 addr_low; 391485d22bbfSMahesh Rajashekhara 391585d22bbfSMahesh Rajashekhara if (aac_convert_sgl == 0) 391685d22bbfSMahesh Rajashekhara return 0; 391785d22bbfSMahesh Rajashekhara 391885d22bbfSMahesh Rajashekhara sge = kmalloc(nseg_new * sizeof(struct sge_ieee1212), GFP_ATOMIC); 391985d22bbfSMahesh Rajashekhara if (sge == NULL) 392085d22bbfSMahesh Rajashekhara return -1; 392185d22bbfSMahesh Rajashekhara 392285d22bbfSMahesh Rajashekhara for (i = 1, pos = 1; i < nseg-1; ++i) { 392385d22bbfSMahesh Rajashekhara for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) { 392485d22bbfSMahesh Rajashekhara addr_low = rio2->sge[i].addrLow + j * pages * PAGE_SIZE; 392585d22bbfSMahesh Rajashekhara sge[pos].addrLow = addr_low; 392685d22bbfSMahesh Rajashekhara sge[pos].addrHigh = rio2->sge[i].addrHigh; 392785d22bbfSMahesh Rajashekhara if (addr_low < rio2->sge[i].addrLow) 392885d22bbfSMahesh Rajashekhara sge[pos].addrHigh++; 392985d22bbfSMahesh Rajashekhara sge[pos].length = pages * PAGE_SIZE; 393085d22bbfSMahesh Rajashekhara sge[pos].flags = 0; 393185d22bbfSMahesh Rajashekhara pos++; 393285d22bbfSMahesh Rajashekhara } 393385d22bbfSMahesh Rajashekhara } 393485d22bbfSMahesh Rajashekhara sge[pos] = rio2->sge[nseg-1]; 393585d22bbfSMahesh Rajashekhara memcpy(&rio2->sge[1], &sge[1], (nseg_new-1)*sizeof(struct sge_ieee1212)); 393685d22bbfSMahesh Rajashekhara 393785d22bbfSMahesh Rajashekhara kfree(sge); 393885d22bbfSMahesh Rajashekhara rio2->sgeCnt = cpu_to_le32(nseg_new); 393985d22bbfSMahesh Rajashekhara rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); 394085d22bbfSMahesh Rajashekhara rio2->sgeNominalSize = pages * PAGE_SIZE; 394185d22bbfSMahesh Rajashekhara return 0; 394285d22bbfSMahesh Rajashekhara } 394385d22bbfSMahesh Rajashekhara 3944ab5d129fSRaghava Aditya Renukunta static long aac_build_sghba(struct scsi_cmnd *scsicmd, 3945ab5d129fSRaghava Aditya Renukunta struct aac_hba_cmd_req *hbacmd, 3946ab5d129fSRaghava Aditya Renukunta int sg_max, 3947ab5d129fSRaghava Aditya Renukunta u64 sg_address) 3948ab5d129fSRaghava Aditya Renukunta { 3949ab5d129fSRaghava Aditya Renukunta unsigned long byte_count = 0; 3950ab5d129fSRaghava Aditya Renukunta int nseg; 3951ab5d129fSRaghava Aditya Renukunta struct scatterlist *sg; 3952ab5d129fSRaghava Aditya Renukunta int i; 3953ab5d129fSRaghava Aditya Renukunta u32 cur_size; 3954ab5d129fSRaghava Aditya Renukunta struct aac_hba_sgl *sge; 3955ab5d129fSRaghava Aditya Renukunta 3956ab5d129fSRaghava Aditya Renukunta 3957ab5d129fSRaghava Aditya Renukunta 3958ab5d129fSRaghava Aditya Renukunta nseg = scsi_dma_map(scsicmd); 3959ab5d129fSRaghava Aditya Renukunta if (nseg <= 0) { 3960ab5d129fSRaghava Aditya Renukunta byte_count = nseg; 3961ab5d129fSRaghava Aditya Renukunta goto out; 3962ab5d129fSRaghava Aditya Renukunta } 3963ab5d129fSRaghava Aditya Renukunta 3964ab5d129fSRaghava Aditya Renukunta if (nseg > HBA_MAX_SG_EMBEDDED) 3965ab5d129fSRaghava Aditya Renukunta sge = &hbacmd->sge[2]; 3966ab5d129fSRaghava Aditya Renukunta else 3967ab5d129fSRaghava Aditya Renukunta sge = &hbacmd->sge[0]; 3968ab5d129fSRaghava Aditya Renukunta 3969ab5d129fSRaghava Aditya Renukunta scsi_for_each_sg(scsicmd, sg, nseg, i) { 3970ab5d129fSRaghava Aditya Renukunta int count = sg_dma_len(sg); 3971ab5d129fSRaghava Aditya Renukunta u64 addr = sg_dma_address(sg); 3972ab5d129fSRaghava Aditya Renukunta 3973ab5d129fSRaghava Aditya Renukunta WARN_ON(i >= sg_max); 3974ab5d129fSRaghava Aditya Renukunta sge->addr_hi = cpu_to_le32((u32)(addr>>32)); 3975ab5d129fSRaghava Aditya Renukunta sge->addr_lo = cpu_to_le32((u32)(addr & 0xffffffff)); 3976ab5d129fSRaghava Aditya Renukunta cur_size = cpu_to_le32(count); 3977ab5d129fSRaghava Aditya Renukunta sge->len = cur_size; 3978ab5d129fSRaghava Aditya Renukunta sge->flags = 0; 3979ab5d129fSRaghava Aditya Renukunta byte_count += count; 3980ab5d129fSRaghava Aditya Renukunta sge++; 3981ab5d129fSRaghava Aditya Renukunta } 3982ab5d129fSRaghava Aditya Renukunta 3983ab5d129fSRaghava Aditya Renukunta sge--; 3984ab5d129fSRaghava Aditya Renukunta /* hba wants the size to be exact */ 3985ab5d129fSRaghava Aditya Renukunta if (byte_count > scsi_bufflen(scsicmd)) { 3986ab5d129fSRaghava Aditya Renukunta u32 temp; 3987ab5d129fSRaghava Aditya Renukunta 3988ab5d129fSRaghava Aditya Renukunta temp = le32_to_cpu(sge->len) - byte_count 3989ab5d129fSRaghava Aditya Renukunta - scsi_bufflen(scsicmd); 3990ab5d129fSRaghava Aditya Renukunta sge->len = cpu_to_le32(temp); 3991ab5d129fSRaghava Aditya Renukunta byte_count = scsi_bufflen(scsicmd); 3992ab5d129fSRaghava Aditya Renukunta } 3993ab5d129fSRaghava Aditya Renukunta 3994ab5d129fSRaghava Aditya Renukunta if (nseg <= HBA_MAX_SG_EMBEDDED) { 3995ab5d129fSRaghava Aditya Renukunta hbacmd->emb_data_desc_count = cpu_to_le32(nseg); 3996ab5d129fSRaghava Aditya Renukunta sge->flags = cpu_to_le32(0x40000000); 3997ab5d129fSRaghava Aditya Renukunta } else { 3998ab5d129fSRaghava Aditya Renukunta /* not embedded */ 3999ab5d129fSRaghava Aditya Renukunta hbacmd->sge[0].flags = cpu_to_le32(0x80000000); 4000ab5d129fSRaghava Aditya Renukunta hbacmd->emb_data_desc_count = (u8)cpu_to_le32(1); 4001ab5d129fSRaghava Aditya Renukunta hbacmd->sge[0].addr_hi = (u32)cpu_to_le32(sg_address >> 32); 4002ab5d129fSRaghava Aditya Renukunta hbacmd->sge[0].addr_lo = 4003ab5d129fSRaghava Aditya Renukunta cpu_to_le32((u32)(sg_address & 0xffffffff)); 4004ab5d129fSRaghava Aditya Renukunta } 4005ab5d129fSRaghava Aditya Renukunta 4006ab5d129fSRaghava Aditya Renukunta /* Check for command underflow */ 4007ab5d129fSRaghava Aditya Renukunta if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 4008ab5d129fSRaghava Aditya Renukunta pr_warn("aacraid: cmd len %08lX cmd underflow %08X\n", 4009ab5d129fSRaghava Aditya Renukunta byte_count, scsicmd->underflow); 4010ab5d129fSRaghava Aditya Renukunta } 4011ab5d129fSRaghava Aditya Renukunta out: 4012ab5d129fSRaghava Aditya Renukunta return byte_count; 4013ab5d129fSRaghava Aditya Renukunta } 4014ab5d129fSRaghava Aditya Renukunta 40151da177e4SLinus Torvalds #ifdef AAC_DETAILED_STATUS_INFO 40161da177e4SLinus Torvalds 40171da177e4SLinus Torvalds struct aac_srb_status_info { 40181da177e4SLinus Torvalds u32 status; 40191da177e4SLinus Torvalds char *str; 40201da177e4SLinus Torvalds }; 40211da177e4SLinus Torvalds 40221da177e4SLinus Torvalds 40231da177e4SLinus Torvalds static struct aac_srb_status_info srb_status_info[] = { 40241da177e4SLinus Torvalds { SRB_STATUS_PENDING, "Pending Status"}, 40251da177e4SLinus Torvalds { SRB_STATUS_SUCCESS, "Success"}, 40261da177e4SLinus Torvalds { SRB_STATUS_ABORTED, "Aborted Command"}, 40271da177e4SLinus Torvalds { SRB_STATUS_ABORT_FAILED, "Abort Failed"}, 40281da177e4SLinus Torvalds { SRB_STATUS_ERROR, "Error Event"}, 40291da177e4SLinus Torvalds { SRB_STATUS_BUSY, "Device Busy"}, 40301da177e4SLinus Torvalds { SRB_STATUS_INVALID_REQUEST, "Invalid Request"}, 40311da177e4SLinus Torvalds { SRB_STATUS_INVALID_PATH_ID, "Invalid Path ID"}, 40321da177e4SLinus Torvalds { SRB_STATUS_NO_DEVICE, "No Device"}, 40331da177e4SLinus Torvalds { SRB_STATUS_TIMEOUT, "Timeout"}, 40341da177e4SLinus Torvalds { SRB_STATUS_SELECTION_TIMEOUT, "Selection Timeout"}, 40351da177e4SLinus Torvalds { SRB_STATUS_COMMAND_TIMEOUT, "Command Timeout"}, 40361da177e4SLinus Torvalds { SRB_STATUS_MESSAGE_REJECTED, "Message Rejected"}, 40371da177e4SLinus Torvalds { SRB_STATUS_BUS_RESET, "Bus Reset"}, 40381da177e4SLinus Torvalds { SRB_STATUS_PARITY_ERROR, "Parity Error"}, 40391da177e4SLinus Torvalds { SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"}, 40401da177e4SLinus Torvalds { SRB_STATUS_NO_HBA, "No HBA"}, 40411da177e4SLinus Torvalds { SRB_STATUS_DATA_OVERRUN, "Data Overrun/Data Underrun"}, 40421da177e4SLinus Torvalds { SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"}, 40431da177e4SLinus Torvalds { SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"}, 40441da177e4SLinus Torvalds { SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"}, 40451da177e4SLinus Torvalds { SRB_STATUS_REQUEST_FLUSHED, "Request Flushed"}, 40461da177e4SLinus Torvalds { SRB_STATUS_DELAYED_RETRY, "Delayed Retry"}, 40471da177e4SLinus Torvalds { SRB_STATUS_INVALID_LUN, "Invalid LUN"}, 40481da177e4SLinus Torvalds { SRB_STATUS_INVALID_TARGET_ID, "Invalid TARGET ID"}, 40491da177e4SLinus Torvalds { SRB_STATUS_BAD_FUNCTION, "Bad Function"}, 40501da177e4SLinus Torvalds { SRB_STATUS_ERROR_RECOVERY, "Error Recovery"}, 40511da177e4SLinus Torvalds { SRB_STATUS_NOT_STARTED, "Not Started"}, 40521da177e4SLinus Torvalds { SRB_STATUS_NOT_IN_USE, "Not In Use"}, 40531da177e4SLinus Torvalds { SRB_STATUS_FORCE_ABORT, "Force Abort"}, 40541da177e4SLinus Torvalds { SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"}, 40551da177e4SLinus Torvalds { 0xff, "Unknown Error"} 40561da177e4SLinus Torvalds }; 40571da177e4SLinus Torvalds 40581da177e4SLinus Torvalds char *aac_get_status_string(u32 status) 40591da177e4SLinus Torvalds { 40601da177e4SLinus Torvalds int i; 40611da177e4SLinus Torvalds 40626391a113STobias Klauser for (i = 0; i < ARRAY_SIZE(srb_status_info); i++) 40636391a113STobias Klauser if (srb_status_info[i].status == status) 40641da177e4SLinus Torvalds return srb_status_info[i].str; 40651da177e4SLinus Torvalds 40661da177e4SLinus Torvalds return "Bad Status Code"; 40671da177e4SLinus Torvalds } 40681da177e4SLinus Torvalds 40691da177e4SLinus Torvalds #endif 4070