18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Adaptec AAC series RAID controller driver 48c2ecf20Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * based on the old aacraid driver that is.. 78c2ecf20Sopenharmony_ci * Adaptec aacraid device driver for Linux. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 108c2ecf20Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 118c2ecf20Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Module Name: 148c2ecf20Sopenharmony_ci * aachba.c 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Abstract: Contains Interfaces to manage IOs. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/completion.h> 268c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 278c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 288c2ecf20Sopenharmony_ci#include <linux/highmem.h> /* For flush_kernel_dcache_page */ 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 348c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 358c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 368c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "aacraid.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* values for inqd_pdt: Peripheral device type in plain English */ 418c2ecf20Sopenharmony_ci#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ 428c2ecf20Sopenharmony_ci#define INQD_PDT_PROC 0x03 /* Processor device */ 438c2ecf20Sopenharmony_ci#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ 448c2ecf20Sopenharmony_ci#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ 458c2ecf20Sopenharmony_ci#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ 468c2ecf20Sopenharmony_ci#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ 498c2ecf20Sopenharmony_ci#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * Sense codes 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define SENCODE_NO_SENSE 0x00 568c2ecf20Sopenharmony_ci#define SENCODE_END_OF_DATA 0x00 578c2ecf20Sopenharmony_ci#define SENCODE_BECOMING_READY 0x04 588c2ecf20Sopenharmony_ci#define SENCODE_INIT_CMD_REQUIRED 0x04 598c2ecf20Sopenharmony_ci#define SENCODE_UNRECOVERED_READ_ERROR 0x11 608c2ecf20Sopenharmony_ci#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A 618c2ecf20Sopenharmony_ci#define SENCODE_INVALID_COMMAND 0x20 628c2ecf20Sopenharmony_ci#define SENCODE_LBA_OUT_OF_RANGE 0x21 638c2ecf20Sopenharmony_ci#define SENCODE_INVALID_CDB_FIELD 0x24 648c2ecf20Sopenharmony_ci#define SENCODE_LUN_NOT_SUPPORTED 0x25 658c2ecf20Sopenharmony_ci#define SENCODE_INVALID_PARAM_FIELD 0x26 668c2ecf20Sopenharmony_ci#define SENCODE_PARAM_NOT_SUPPORTED 0x26 678c2ecf20Sopenharmony_ci#define SENCODE_PARAM_VALUE_INVALID 0x26 688c2ecf20Sopenharmony_ci#define SENCODE_RESET_OCCURRED 0x29 698c2ecf20Sopenharmony_ci#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E 708c2ecf20Sopenharmony_ci#define SENCODE_INQUIRY_DATA_CHANGED 0x3F 718c2ecf20Sopenharmony_ci#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 728c2ecf20Sopenharmony_ci#define SENCODE_DIAGNOSTIC_FAILURE 0x40 738c2ecf20Sopenharmony_ci#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 748c2ecf20Sopenharmony_ci#define SENCODE_INVALID_MESSAGE_ERROR 0x49 758c2ecf20Sopenharmony_ci#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c 768c2ecf20Sopenharmony_ci#define SENCODE_OVERLAPPED_COMMAND 0x4E 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Additional sense codes 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define ASENCODE_NO_SENSE 0x00 838c2ecf20Sopenharmony_ci#define ASENCODE_END_OF_DATA 0x05 848c2ecf20Sopenharmony_ci#define ASENCODE_BECOMING_READY 0x01 858c2ecf20Sopenharmony_ci#define ASENCODE_INIT_CMD_REQUIRED 0x02 868c2ecf20Sopenharmony_ci#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 878c2ecf20Sopenharmony_ci#define ASENCODE_INVALID_COMMAND 0x00 888c2ecf20Sopenharmony_ci#define ASENCODE_LBA_OUT_OF_RANGE 0x00 898c2ecf20Sopenharmony_ci#define ASENCODE_INVALID_CDB_FIELD 0x00 908c2ecf20Sopenharmony_ci#define ASENCODE_LUN_NOT_SUPPORTED 0x00 918c2ecf20Sopenharmony_ci#define ASENCODE_INVALID_PARAM_FIELD 0x00 928c2ecf20Sopenharmony_ci#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 938c2ecf20Sopenharmony_ci#define ASENCODE_PARAM_VALUE_INVALID 0x02 948c2ecf20Sopenharmony_ci#define ASENCODE_RESET_OCCURRED 0x00 958c2ecf20Sopenharmony_ci#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 968c2ecf20Sopenharmony_ci#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 978c2ecf20Sopenharmony_ci#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 988c2ecf20Sopenharmony_ci#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 998c2ecf20Sopenharmony_ci#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 1008c2ecf20Sopenharmony_ci#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 1018c2ecf20Sopenharmony_ci#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 1028c2ecf20Sopenharmony_ci#define ASENCODE_OVERLAPPED_COMMAND 0x00 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define BYTE0(x) (unsigned char)(x) 1058c2ecf20Sopenharmony_ci#define BYTE1(x) (unsigned char)((x) >> 8) 1068c2ecf20Sopenharmony_ci#define BYTE2(x) (unsigned char)((x) >> 16) 1078c2ecf20Sopenharmony_ci#define BYTE3(x) (unsigned char)((x) >> 24) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* MODE_SENSE data format */ 1108c2ecf20Sopenharmony_citypedef struct { 1118c2ecf20Sopenharmony_ci struct { 1128c2ecf20Sopenharmony_ci u8 data_length; 1138c2ecf20Sopenharmony_ci u8 med_type; 1148c2ecf20Sopenharmony_ci u8 dev_par; 1158c2ecf20Sopenharmony_ci u8 bd_length; 1168c2ecf20Sopenharmony_ci } __attribute__((packed)) hd; 1178c2ecf20Sopenharmony_ci struct { 1188c2ecf20Sopenharmony_ci u8 dens_code; 1198c2ecf20Sopenharmony_ci u8 block_count[3]; 1208c2ecf20Sopenharmony_ci u8 reserved; 1218c2ecf20Sopenharmony_ci u8 block_length[3]; 1228c2ecf20Sopenharmony_ci } __attribute__((packed)) bd; 1238c2ecf20Sopenharmony_ci u8 mpc_buf[3]; 1248c2ecf20Sopenharmony_ci} __attribute__((packed)) aac_modep_data; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* MODE_SENSE_10 data format */ 1278c2ecf20Sopenharmony_citypedef struct { 1288c2ecf20Sopenharmony_ci struct { 1298c2ecf20Sopenharmony_ci u8 data_length[2]; 1308c2ecf20Sopenharmony_ci u8 med_type; 1318c2ecf20Sopenharmony_ci u8 dev_par; 1328c2ecf20Sopenharmony_ci u8 rsrvd[2]; 1338c2ecf20Sopenharmony_ci u8 bd_length[2]; 1348c2ecf20Sopenharmony_ci } __attribute__((packed)) hd; 1358c2ecf20Sopenharmony_ci struct { 1368c2ecf20Sopenharmony_ci u8 dens_code; 1378c2ecf20Sopenharmony_ci u8 block_count[3]; 1388c2ecf20Sopenharmony_ci u8 reserved; 1398c2ecf20Sopenharmony_ci u8 block_length[3]; 1408c2ecf20Sopenharmony_ci } __attribute__((packed)) bd; 1418c2ecf20Sopenharmony_ci u8 mpc_buf[3]; 1428c2ecf20Sopenharmony_ci} __attribute__((packed)) aac_modep10_data; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/*------------------------------------------------------------------------------ 1458c2ecf20Sopenharmony_ci * S T R U C T S / T Y P E D E F S 1468c2ecf20Sopenharmony_ci *----------------------------------------------------------------------------*/ 1478c2ecf20Sopenharmony_ci/* SCSI inquiry data */ 1488c2ecf20Sopenharmony_cistruct inquiry_data { 1498c2ecf20Sopenharmony_ci u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ 1508c2ecf20Sopenharmony_ci u8 inqd_dtq; /* RMB | Device Type Qualifier */ 1518c2ecf20Sopenharmony_ci u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ 1528c2ecf20Sopenharmony_ci u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ 1538c2ecf20Sopenharmony_ci u8 inqd_len; /* Additional length (n-4) */ 1548c2ecf20Sopenharmony_ci u8 inqd_pad1[2];/* Reserved - must be zero */ 1558c2ecf20Sopenharmony_ci u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ 1568c2ecf20Sopenharmony_ci u8 inqd_vid[8]; /* Vendor ID */ 1578c2ecf20Sopenharmony_ci u8 inqd_pid[16];/* Product ID */ 1588c2ecf20Sopenharmony_ci u8 inqd_prl[4]; /* Product Revision Level */ 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* Added for VPD 0x83 */ 1628c2ecf20Sopenharmony_cistruct tvpd_id_descriptor_type_1 { 1638c2ecf20Sopenharmony_ci u8 codeset:4; /* VPD_CODE_SET */ 1648c2ecf20Sopenharmony_ci u8 reserved:4; 1658c2ecf20Sopenharmony_ci u8 identifiertype:4; /* VPD_IDENTIFIER_TYPE */ 1668c2ecf20Sopenharmony_ci u8 reserved2:4; 1678c2ecf20Sopenharmony_ci u8 reserved3; 1688c2ecf20Sopenharmony_ci u8 identifierlength; 1698c2ecf20Sopenharmony_ci u8 venid[8]; 1708c2ecf20Sopenharmony_ci u8 productid[16]; 1718c2ecf20Sopenharmony_ci u8 serialnumber[8]; /* SN in ASCII */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistruct tvpd_id_descriptor_type_2 { 1768c2ecf20Sopenharmony_ci u8 codeset:4; /* VPD_CODE_SET */ 1778c2ecf20Sopenharmony_ci u8 reserved:4; 1788c2ecf20Sopenharmony_ci u8 identifiertype:4; /* VPD_IDENTIFIER_TYPE */ 1798c2ecf20Sopenharmony_ci u8 reserved2:4; 1808c2ecf20Sopenharmony_ci u8 reserved3; 1818c2ecf20Sopenharmony_ci u8 identifierlength; 1828c2ecf20Sopenharmony_ci struct teu64id { 1838c2ecf20Sopenharmony_ci u32 Serial; 1848c2ecf20Sopenharmony_ci /* The serial number supposed to be 40 bits, 1858c2ecf20Sopenharmony_ci * bit we only support 32, so make the last byte zero. */ 1868c2ecf20Sopenharmony_ci u8 reserved; 1878c2ecf20Sopenharmony_ci u8 venid[3]; 1888c2ecf20Sopenharmony_ci } eu64id; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistruct tvpd_id_descriptor_type_3 { 1938c2ecf20Sopenharmony_ci u8 codeset : 4; /* VPD_CODE_SET */ 1948c2ecf20Sopenharmony_ci u8 reserved : 4; 1958c2ecf20Sopenharmony_ci u8 identifiertype : 4; /* VPD_IDENTIFIER_TYPE */ 1968c2ecf20Sopenharmony_ci u8 reserved2 : 4; 1978c2ecf20Sopenharmony_ci u8 reserved3; 1988c2ecf20Sopenharmony_ci u8 identifierlength; 1998c2ecf20Sopenharmony_ci u8 Identifier[16]; 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistruct tvpd_page83 { 2038c2ecf20Sopenharmony_ci u8 DeviceType:5; 2048c2ecf20Sopenharmony_ci u8 DeviceTypeQualifier:3; 2058c2ecf20Sopenharmony_ci u8 PageCode; 2068c2ecf20Sopenharmony_ci u8 reserved; 2078c2ecf20Sopenharmony_ci u8 PageLength; 2088c2ecf20Sopenharmony_ci struct tvpd_id_descriptor_type_1 type1; 2098c2ecf20Sopenharmony_ci struct tvpd_id_descriptor_type_2 type2; 2108c2ecf20Sopenharmony_ci struct tvpd_id_descriptor_type_3 type3; 2118c2ecf20Sopenharmony_ci}; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * M O D U L E G L O B A L S 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap); 2188c2ecf20Sopenharmony_cistatic long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg); 2198c2ecf20Sopenharmony_cistatic long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg); 2208c2ecf20Sopenharmony_cistatic long aac_build_sgraw2(struct scsi_cmnd *scsicmd, 2218c2ecf20Sopenharmony_ci struct aac_raw_io2 *rio2, int sg_max); 2228c2ecf20Sopenharmony_cistatic long aac_build_sghba(struct scsi_cmnd *scsicmd, 2238c2ecf20Sopenharmony_ci struct aac_hba_cmd_req *hbacmd, 2248c2ecf20Sopenharmony_ci int sg_max, u64 sg_address); 2258c2ecf20Sopenharmony_cistatic int aac_convert_sgraw2(struct aac_raw_io2 *rio2, 2268c2ecf20Sopenharmony_ci int pages, int nseg, int nseg_new); 2278c2ecf20Sopenharmony_cistatic int aac_send_srb_fib(struct scsi_cmnd* scsicmd); 2288c2ecf20Sopenharmony_cistatic int aac_send_hba_fib(struct scsi_cmnd *scsicmd); 2298c2ecf20Sopenharmony_ci#ifdef AAC_DETAILED_STATUS_INFO 2308c2ecf20Sopenharmony_cistatic char *aac_get_status_string(u32 status); 2318c2ecf20Sopenharmony_ci#endif 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* 2348c2ecf20Sopenharmony_ci * Non dasd selection is handled entirely in aachba now 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int nondasd = -1; 2388c2ecf20Sopenharmony_cistatic int aac_cache = 2; /* WCE=0 to avoid performance problems */ 2398c2ecf20Sopenharmony_cistatic int dacmode = -1; 2408c2ecf20Sopenharmony_ciint aac_msi; 2418c2ecf20Sopenharmony_ciint aac_commit = -1; 2428c2ecf20Sopenharmony_ciint startup_timeout = 180; 2438c2ecf20Sopenharmony_ciint aif_timeout = 120; 2448c2ecf20Sopenharmony_ciint aac_sync_mode; /* Only Sync. transfer - disabled */ 2458c2ecf20Sopenharmony_cistatic int aac_convert_sgl = 1; /* convert non-conformable s/g list - enabled */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cimodule_param(aac_sync_mode, int, S_IRUGO|S_IWUSR); 2488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode" 2498c2ecf20Sopenharmony_ci " 0=off, 1=on"); 2508c2ecf20Sopenharmony_cimodule_param(aac_convert_sgl, int, S_IRUGO|S_IWUSR); 2518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aac_convert_sgl, "Convert non-conformable s/g list" 2528c2ecf20Sopenharmony_ci " 0=off, 1=on"); 2538c2ecf20Sopenharmony_cimodule_param(nondasd, int, S_IRUGO|S_IWUSR); 2548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices." 2558c2ecf20Sopenharmony_ci " 0=off, 1=on"); 2568c2ecf20Sopenharmony_cimodule_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); 2578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n" 2588c2ecf20Sopenharmony_ci "\tbit 0 - Disable FUA in WRITE SCSI commands\n" 2598c2ecf20Sopenharmony_ci "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n" 2608c2ecf20Sopenharmony_ci "\tbit 2 - Disable only if Battery is protecting Cache"); 2618c2ecf20Sopenharmony_cimodule_param(dacmode, int, S_IRUGO|S_IWUSR); 2628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC." 2638c2ecf20Sopenharmony_ci " 0=off, 1=on"); 2648c2ecf20Sopenharmony_cimodule_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); 2658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" 2668c2ecf20Sopenharmony_ci " adapter for foreign arrays.\n" 2678c2ecf20Sopenharmony_ci "This is typically needed in systems that do not have a BIOS." 2688c2ecf20Sopenharmony_ci " 0=off, 1=on"); 2698c2ecf20Sopenharmony_cimodule_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); 2708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msi, "IRQ handling." 2718c2ecf20Sopenharmony_ci " 0=PIC(default), 1=MSI, 2=MSI-X)"); 2728c2ecf20Sopenharmony_cimodule_param(startup_timeout, int, S_IRUGO|S_IWUSR); 2738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" 2748c2ecf20Sopenharmony_ci " adapter to have it's kernel up and\n" 2758c2ecf20Sopenharmony_ci "running. This is typically adjusted for large systems that do not" 2768c2ecf20Sopenharmony_ci " have a BIOS."); 2778c2ecf20Sopenharmony_cimodule_param(aif_timeout, int, S_IRUGO|S_IWUSR); 2788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for" 2798c2ecf20Sopenharmony_ci " applications to pick up AIFs before\n" 2808c2ecf20Sopenharmony_ci "deregistering them. This is typically adjusted for heavily burdened" 2818c2ecf20Sopenharmony_ci " systems."); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciint aac_fib_dump; 2848c2ecf20Sopenharmony_cimodule_param(aac_fib_dump, int, 0644); 2858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aac_fib_dump, "Dump controller fibs prior to IOP_RESET 0=off, 1=on"); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciint numacb = -1; 2888c2ecf20Sopenharmony_cimodule_param(numacb, int, S_IRUGO|S_IWUSR); 2898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control" 2908c2ecf20Sopenharmony_ci " blocks (FIB) allocated. Valid values are 512 and down. Default is" 2918c2ecf20Sopenharmony_ci " to use suggestion from Firmware."); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int acbsize = -1; 2948c2ecf20Sopenharmony_cimodule_param(acbsize, int, S_IRUGO|S_IWUSR); 2958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)" 2968c2ecf20Sopenharmony_ci " size. Valid values are 512, 2048, 4096 and 8192. Default is to use" 2978c2ecf20Sopenharmony_ci " suggestion from Firmware."); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciint update_interval = 30 * 60; 3008c2ecf20Sopenharmony_cimodule_param(update_interval, int, S_IRUGO|S_IWUSR); 3018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(update_interval, "Interval in seconds between time sync" 3028c2ecf20Sopenharmony_ci " updates issued to adapter."); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciint check_interval = 60; 3058c2ecf20Sopenharmony_cimodule_param(check_interval, int, S_IRUGO|S_IWUSR); 3068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" 3078c2ecf20Sopenharmony_ci " checks."); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ciint aac_check_reset = 1; 3108c2ecf20Sopenharmony_cimodule_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); 3118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the" 3128c2ecf20Sopenharmony_ci " adapter. a value of -1 forces the reset to adapters programmed to" 3138c2ecf20Sopenharmony_ci " ignore it."); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciint expose_physicals = -1; 3168c2ecf20Sopenharmony_cimodule_param(expose_physicals, int, S_IRUGO|S_IWUSR); 3178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays." 3188c2ecf20Sopenharmony_ci " -1=protect 0=off, 1=on"); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ciint aac_reset_devices; 3218c2ecf20Sopenharmony_cimodule_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); 3228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int aac_wwn = 1; 3258c2ecf20Sopenharmony_cimodule_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR); 3268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n" 3278c2ecf20Sopenharmony_ci "\t0 - Disable\n" 3288c2ecf20Sopenharmony_ci "\t1 - Array Meta Data Signature (default)\n" 3298c2ecf20Sopenharmony_ci "\t2 - Adapter Serial Number"); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic inline int aac_valid_context(struct scsi_cmnd *scsicmd, 3338c2ecf20Sopenharmony_ci struct fib *fibptr) { 3348c2ecf20Sopenharmony_ci struct scsi_device *device; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (unlikely(!scsicmd || !scsicmd->scsi_done)) { 3378c2ecf20Sopenharmony_ci dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n")); 3388c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; 3428c2ecf20Sopenharmony_ci device = scsicmd->device; 3438c2ecf20Sopenharmony_ci if (unlikely(!device)) { 3448c2ecf20Sopenharmony_ci dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n")); 3458c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci return 1; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * aac_get_config_status - check the adapter configuration 3538c2ecf20Sopenharmony_ci * @dev: aac driver data 3548c2ecf20Sopenharmony_ci * @commit_flag: force sending CT_COMMIT_CONFIG 3558c2ecf20Sopenharmony_ci * 3568c2ecf20Sopenharmony_ci * Query config status, and commit the configuration if needed. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ciint aac_get_config_status(struct aac_dev *dev, int commit_flag) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int status = 0; 3618c2ecf20Sopenharmony_ci struct fib * fibptr; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!(fibptr = aac_fib_alloc(dev))) 3648c2ecf20Sopenharmony_ci return -ENOMEM; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 3678c2ecf20Sopenharmony_ci { 3688c2ecf20Sopenharmony_ci struct aac_get_config_status *dinfo; 3698c2ecf20Sopenharmony_ci dinfo = (struct aac_get_config_status *) fib_data(fibptr); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_ContainerConfig); 3728c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS); 3738c2ecf20Sopenharmony_ci dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data)); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 3778c2ecf20Sopenharmony_ci fibptr, 3788c2ecf20Sopenharmony_ci sizeof (struct aac_get_config_status), 3798c2ecf20Sopenharmony_ci FsaNormal, 3808c2ecf20Sopenharmony_ci 1, 1, 3818c2ecf20Sopenharmony_ci NULL, NULL); 3828c2ecf20Sopenharmony_ci if (status < 0) { 3838c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n"); 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci struct aac_get_config_status_resp *reply 3868c2ecf20Sopenharmony_ci = (struct aac_get_config_status_resp *) fib_data(fibptr); 3878c2ecf20Sopenharmony_ci dprintk((KERN_WARNING 3888c2ecf20Sopenharmony_ci "aac_get_config_status: response=%d status=%d action=%d\n", 3898c2ecf20Sopenharmony_ci le32_to_cpu(reply->response), 3908c2ecf20Sopenharmony_ci le32_to_cpu(reply->status), 3918c2ecf20Sopenharmony_ci le32_to_cpu(reply->data.action))); 3928c2ecf20Sopenharmony_ci if ((le32_to_cpu(reply->response) != ST_OK) || 3938c2ecf20Sopenharmony_ci (le32_to_cpu(reply->status) != CT_OK) || 3948c2ecf20Sopenharmony_ci (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) { 3958c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n"); 3968c2ecf20Sopenharmony_ci status = -EINVAL; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci /* Do not set XferState to zero unless receives a response from F/W */ 4008c2ecf20Sopenharmony_ci if (status >= 0) 4018c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ 4048c2ecf20Sopenharmony_ci if (status >= 0) { 4058c2ecf20Sopenharmony_ci if ((aac_commit == 1) || commit_flag) { 4068c2ecf20Sopenharmony_ci struct aac_commit_config * dinfo; 4078c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 4088c2ecf20Sopenharmony_ci dinfo = (struct aac_commit_config *) fib_data(fibptr); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_ContainerConfig); 4118c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 4148c2ecf20Sopenharmony_ci fibptr, 4158c2ecf20Sopenharmony_ci sizeof (struct aac_commit_config), 4168c2ecf20Sopenharmony_ci FsaNormal, 4178c2ecf20Sopenharmony_ci 1, 1, 4188c2ecf20Sopenharmony_ci NULL, NULL); 4198c2ecf20Sopenharmony_ci /* Do not set XferState to zero unless 4208c2ecf20Sopenharmony_ci * receives a response from F/W */ 4218c2ecf20Sopenharmony_ci if (status >= 0) 4228c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 4238c2ecf20Sopenharmony_ci } else if (aac_commit == 0) { 4248c2ecf20Sopenharmony_ci printk(KERN_WARNING 4258c2ecf20Sopenharmony_ci "aac_get_config_status: Foreign device configurations are being ignored\n"); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci /* FIB should be freed only after getting the response from the F/W */ 4298c2ecf20Sopenharmony_ci if (status != -ERESTARTSYS) 4308c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 4318c2ecf20Sopenharmony_ci return status; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void aac_expose_phy_device(struct scsi_cmnd *scsicmd) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci char inq_data; 4378c2ecf20Sopenharmony_ci scsi_sg_copy_to_buffer(scsicmd, &inq_data, sizeof(inq_data)); 4388c2ecf20Sopenharmony_ci if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) { 4398c2ecf20Sopenharmony_ci inq_data &= 0xdf; 4408c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/** 4458c2ecf20Sopenharmony_ci * aac_get_containers - list containers 4468c2ecf20Sopenharmony_ci * @dev: aac driver data 4478c2ecf20Sopenharmony_ci * 4488c2ecf20Sopenharmony_ci * Make a list of all containers on this controller 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_ciint aac_get_containers(struct aac_dev *dev) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr; 4538c2ecf20Sopenharmony_ci u32 index; 4548c2ecf20Sopenharmony_ci int status = 0; 4558c2ecf20Sopenharmony_ci struct fib * fibptr; 4568c2ecf20Sopenharmony_ci struct aac_get_container_count *dinfo; 4578c2ecf20Sopenharmony_ci struct aac_get_container_count_resp *dresp; 4588c2ecf20Sopenharmony_ci int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (!(fibptr = aac_fib_alloc(dev))) 4618c2ecf20Sopenharmony_ci return -ENOMEM; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 4648c2ecf20Sopenharmony_ci dinfo = (struct aac_get_container_count *) fib_data(fibptr); 4658c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_ContainerConfig); 4668c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 4698c2ecf20Sopenharmony_ci fibptr, 4708c2ecf20Sopenharmony_ci sizeof (struct aac_get_container_count), 4718c2ecf20Sopenharmony_ci FsaNormal, 4728c2ecf20Sopenharmony_ci 1, 1, 4738c2ecf20Sopenharmony_ci NULL, NULL); 4748c2ecf20Sopenharmony_ci if (status >= 0) { 4758c2ecf20Sopenharmony_ci dresp = (struct aac_get_container_count_resp *)fib_data(fibptr); 4768c2ecf20Sopenharmony_ci maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); 4778c2ecf20Sopenharmony_ci if (fibptr->dev->supplement_adapter_info.supported_options2 & 4788c2ecf20Sopenharmony_ci AAC_OPTION_SUPPORTED_240_VOLUMES) { 4798c2ecf20Sopenharmony_ci maximum_num_containers = 4808c2ecf20Sopenharmony_ci le32_to_cpu(dresp->MaxSimpleVolumes); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci /* FIB should be freed only after getting the response from the F/W */ 4858c2ecf20Sopenharmony_ci if (status != -ERESTARTSYS) 4868c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) 4898c2ecf20Sopenharmony_ci maximum_num_containers = MAXIMUM_NUM_CONTAINERS; 4908c2ecf20Sopenharmony_ci if (dev->fsa_dev == NULL || 4918c2ecf20Sopenharmony_ci dev->maximum_num_containers != maximum_num_containers) { 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci fsa_dev_ptr = dev->fsa_dev; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci dev->fsa_dev = kcalloc(maximum_num_containers, 4968c2ecf20Sopenharmony_ci sizeof(*fsa_dev_ptr), GFP_KERNEL); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci kfree(fsa_dev_ptr); 4998c2ecf20Sopenharmony_ci fsa_dev_ptr = NULL; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (!dev->fsa_dev) 5038c2ecf20Sopenharmony_ci return -ENOMEM; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci dev->maximum_num_containers = maximum_num_containers; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci for (index = 0; index < dev->maximum_num_containers; index++) { 5088c2ecf20Sopenharmony_ci dev->fsa_dev[index].devname[0] = '\0'; 5098c2ecf20Sopenharmony_ci dev->fsa_dev[index].valid = 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci status = aac_probe_container(dev, index); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (status < 0) { 5148c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci return status; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void get_container_name_callback(void *context, struct fib * fibptr) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct aac_get_name_resp * get_name_reply; 5248c2ecf20Sopenharmony_ci struct scsi_cmnd * scsicmd; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 5298c2ecf20Sopenharmony_ci return; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); 5328c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr); 5358c2ecf20Sopenharmony_ci /* Failure is irrelevant, using default value instead */ 5368c2ecf20Sopenharmony_ci if ((le32_to_cpu(get_name_reply->status) == CT_OK) 5378c2ecf20Sopenharmony_ci && (get_name_reply->data[0] != '\0')) { 5388c2ecf20Sopenharmony_ci char *sp = get_name_reply->data; 5398c2ecf20Sopenharmony_ci int data_size = sizeof_field(struct aac_get_name_resp, data); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci sp[data_size - 1] = '\0'; 5428c2ecf20Sopenharmony_ci while (*sp == ' ') 5438c2ecf20Sopenharmony_ci ++sp; 5448c2ecf20Sopenharmony_ci if (*sp) { 5458c2ecf20Sopenharmony_ci struct inquiry_data inq; 5468c2ecf20Sopenharmony_ci char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; 5478c2ecf20Sopenharmony_ci int count = sizeof(d); 5488c2ecf20Sopenharmony_ci char *dp = d; 5498c2ecf20Sopenharmony_ci do { 5508c2ecf20Sopenharmony_ci *dp++ = (*sp) ? *sp++ : ' '; 5518c2ecf20Sopenharmony_ci } while (--count > 0); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq)); 5548c2ecf20Sopenharmony_ci memcpy(inq.inqd_pid, d, sizeof(d)); 5558c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq)); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 5628c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/* 5668c2ecf20Sopenharmony_ci * aac_get_container_name - get container name, none blocking. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_cistatic int aac_get_container_name(struct scsi_cmnd * scsicmd) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci int status; 5718c2ecf20Sopenharmony_ci int data_size; 5728c2ecf20Sopenharmony_ci struct aac_get_name *dinfo; 5738c2ecf20Sopenharmony_ci struct fib * cmd_fibcontext; 5748c2ecf20Sopenharmony_ci struct aac_dev * dev; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci data_size = sizeof_field(struct aac_get_name_resp, data); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci aac_fib_init(cmd_fibcontext); 5838c2ecf20Sopenharmony_ci dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext); 5848c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_ContainerConfig); 5878c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(CT_READ_NAME); 5888c2ecf20Sopenharmony_ci dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); 5898c2ecf20Sopenharmony_ci dinfo->count = cpu_to_le32(data_size - 1); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 5928c2ecf20Sopenharmony_ci cmd_fibcontext, 5938c2ecf20Sopenharmony_ci sizeof(struct aac_get_name_resp), 5948c2ecf20Sopenharmony_ci FsaNormal, 5958c2ecf20Sopenharmony_ci 0, 1, 5968c2ecf20Sopenharmony_ci (fib_callback)get_container_name_callback, 5978c2ecf20Sopenharmony_ci (void *) scsicmd); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* 6008c2ecf20Sopenharmony_ci * Check that the command queued to the controller 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); 6068c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 6078c2ecf20Sopenharmony_ci return -1; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int aac_probe_container_callback2(struct scsi_cmnd * scsicmd) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1)) 6158c2ecf20Sopenharmony_ci return aac_scsi_cmd(scsicmd); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16; 6188c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic void _aac_probe_container2(void * context, struct fib * fibptr) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr; 6258c2ecf20Sopenharmony_ci int (*callback)(struct scsi_cmnd *); 6268c2ecf20Sopenharmony_ci struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; 6278c2ecf20Sopenharmony_ci int i; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 6318c2ecf20Sopenharmony_ci return; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci scsicmd->SCp.Status = 0; 6348c2ecf20Sopenharmony_ci fsa_dev_ptr = fibptr->dev->fsa_dev; 6358c2ecf20Sopenharmony_ci if (fsa_dev_ptr) { 6368c2ecf20Sopenharmony_ci struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr); 6378c2ecf20Sopenharmony_ci __le32 sup_options2; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci fsa_dev_ptr += scmd_id(scsicmd); 6408c2ecf20Sopenharmony_ci sup_options2 = 6418c2ecf20Sopenharmony_ci fibptr->dev->supplement_adapter_info.supported_options2; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if ((le32_to_cpu(dresp->status) == ST_OK) && 6448c2ecf20Sopenharmony_ci (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && 6458c2ecf20Sopenharmony_ci (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { 6468c2ecf20Sopenharmony_ci if (!(sup_options2 & AAC_OPTION_VARIABLE_BLOCK_SIZE)) { 6478c2ecf20Sopenharmony_ci dresp->mnt[0].fileinfo.bdevinfo.block_size = 0x200; 6488c2ecf20Sopenharmony_ci fsa_dev_ptr->block_size = 0x200; 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci fsa_dev_ptr->block_size = 6518c2ecf20Sopenharmony_ci le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 6548c2ecf20Sopenharmony_ci fsa_dev_ptr->identifier[i] = 6558c2ecf20Sopenharmony_ci dresp->mnt[0].fileinfo.bdevinfo 6568c2ecf20Sopenharmony_ci .identifier[i]; 6578c2ecf20Sopenharmony_ci fsa_dev_ptr->valid = 1; 6588c2ecf20Sopenharmony_ci /* sense_key holds the current state of the spin-up */ 6598c2ecf20Sopenharmony_ci if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY)) 6608c2ecf20Sopenharmony_ci fsa_dev_ptr->sense_data.sense_key = NOT_READY; 6618c2ecf20Sopenharmony_ci else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY) 6628c2ecf20Sopenharmony_ci fsa_dev_ptr->sense_data.sense_key = NO_SENSE; 6638c2ecf20Sopenharmony_ci fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); 6648c2ecf20Sopenharmony_ci fsa_dev_ptr->size 6658c2ecf20Sopenharmony_ci = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + 6668c2ecf20Sopenharmony_ci (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); 6678c2ecf20Sopenharmony_ci fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci if ((fsa_dev_ptr->valid & 1) == 0) 6708c2ecf20Sopenharmony_ci fsa_dev_ptr->valid = 0; 6718c2ecf20Sopenharmony_ci scsicmd->SCp.Status = le32_to_cpu(dresp->count); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 6748c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 6758c2ecf20Sopenharmony_ci callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); 6768c2ecf20Sopenharmony_ci scsicmd->SCp.ptr = NULL; 6778c2ecf20Sopenharmony_ci (*callback)(scsicmd); 6788c2ecf20Sopenharmony_ci return; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void _aac_probe_container1(void * context, struct fib * fibptr) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct scsi_cmnd * scsicmd; 6848c2ecf20Sopenharmony_ci struct aac_mount * dresp; 6858c2ecf20Sopenharmony_ci struct aac_query_mount *dinfo; 6868c2ecf20Sopenharmony_ci int status; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci dresp = (struct aac_mount *) fib_data(fibptr); 6898c2ecf20Sopenharmony_ci if (!aac_supports_2T(fibptr->dev)) { 6908c2ecf20Sopenharmony_ci dresp->mnt[0].capacityhigh = 0; 6918c2ecf20Sopenharmony_ci if ((le32_to_cpu(dresp->status) == ST_OK) && 6928c2ecf20Sopenharmony_ci (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { 6938c2ecf20Sopenharmony_ci _aac_probe_container2(context, fibptr); 6948c2ecf20Sopenharmony_ci return; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 7008c2ecf20Sopenharmony_ci return; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci dinfo = (struct aac_query_mount *)fib_data(fibptr); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (fibptr->dev->supplement_adapter_info.supported_options2 & 7078c2ecf20Sopenharmony_ci AAC_OPTION_VARIABLE_BLOCK_SIZE) 7088c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_NameServeAllBlk); 7098c2ecf20Sopenharmony_ci else 7108c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_NameServe64); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci dinfo->count = cpu_to_le32(scmd_id(scsicmd)); 7138c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(FT_FILESYS); 7148c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 7178c2ecf20Sopenharmony_ci fibptr, 7188c2ecf20Sopenharmony_ci sizeof(struct aac_query_mount), 7198c2ecf20Sopenharmony_ci FsaNormal, 7208c2ecf20Sopenharmony_ci 0, 1, 7218c2ecf20Sopenharmony_ci _aac_probe_container2, 7228c2ecf20Sopenharmony_ci (void *) scsicmd); 7238c2ecf20Sopenharmony_ci /* 7248c2ecf20Sopenharmony_ci * Check that the command queued to the controller 7258c2ecf20Sopenharmony_ci */ 7268c2ecf20Sopenharmony_ci if (status < 0 && status != -EINPROGRESS) { 7278c2ecf20Sopenharmony_ci /* Inherit results from VM_NameServe, if any */ 7288c2ecf20Sopenharmony_ci dresp->status = cpu_to_le32(ST_OK); 7298c2ecf20Sopenharmony_ci _aac_probe_container2(context, fibptr); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct fib * fibptr; 7368c2ecf20Sopenharmony_ci int status = -ENOMEM; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) { 7398c2ecf20Sopenharmony_ci struct aac_query_mount *dinfo; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci dinfo = (struct aac_query_mount *)fib_data(fibptr); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (fibptr->dev->supplement_adapter_info.supported_options2 & 7468c2ecf20Sopenharmony_ci AAC_OPTION_VARIABLE_BLOCK_SIZE) 7478c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_NameServeAllBlk); 7488c2ecf20Sopenharmony_ci else 7498c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_NameServe); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci dinfo->count = cpu_to_le32(scmd_id(scsicmd)); 7528c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(FT_FILESYS); 7538c2ecf20Sopenharmony_ci scsicmd->SCp.ptr = (char *)callback; 7548c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 7578c2ecf20Sopenharmony_ci fibptr, 7588c2ecf20Sopenharmony_ci sizeof(struct aac_query_mount), 7598c2ecf20Sopenharmony_ci FsaNormal, 7608c2ecf20Sopenharmony_ci 0, 1, 7618c2ecf20Sopenharmony_ci _aac_probe_container1, 7628c2ecf20Sopenharmony_ci (void *) scsicmd); 7638c2ecf20Sopenharmony_ci /* 7648c2ecf20Sopenharmony_ci * Check that the command queued to the controller 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 7678c2ecf20Sopenharmony_ci return 0; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (status < 0) { 7708c2ecf20Sopenharmony_ci scsicmd->SCp.ptr = NULL; 7718c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 7728c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci if (status < 0) { 7768c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; 7778c2ecf20Sopenharmony_ci if (fsa_dev_ptr) { 7788c2ecf20Sopenharmony_ci fsa_dev_ptr += scmd_id(scsicmd); 7798c2ecf20Sopenharmony_ci if ((fsa_dev_ptr->valid & 1) == 0) { 7808c2ecf20Sopenharmony_ci fsa_dev_ptr->valid = 0; 7818c2ecf20Sopenharmony_ci return (*callback)(scsicmd); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci return status; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci/** 7898c2ecf20Sopenharmony_ci * aac_probe_container - query a logical volume 7908c2ecf20Sopenharmony_ci * @scsicmd: the scsi command block 7918c2ecf20Sopenharmony_ci * 7928c2ecf20Sopenharmony_ci * Queries the controller about the given volume. The volume information 7938c2ecf20Sopenharmony_ci * is updated in the struct fsa_dev_info structure rather than returned. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_cistatic int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci scsicmd->device = NULL; 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic void aac_probe_container_scsi_done(struct scsi_cmnd *scsi_cmnd) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci aac_probe_container_callback1(scsi_cmnd); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ciint aac_probe_container(struct aac_dev *dev, int cid) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); 8098c2ecf20Sopenharmony_ci struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL); 8108c2ecf20Sopenharmony_ci int status; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (!scsicmd || !scsidev) { 8138c2ecf20Sopenharmony_ci kfree(scsicmd); 8148c2ecf20Sopenharmony_ci kfree(scsidev); 8158c2ecf20Sopenharmony_ci return -ENOMEM; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci scsicmd->scsi_done = aac_probe_container_scsi_done; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci scsicmd->device = scsidev; 8208c2ecf20Sopenharmony_ci scsidev->sdev_state = 0; 8218c2ecf20Sopenharmony_ci scsidev->id = cid; 8228c2ecf20Sopenharmony_ci scsidev->host = dev->scsi_host_ptr; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0) 8258c2ecf20Sopenharmony_ci while (scsicmd->device == scsidev) 8268c2ecf20Sopenharmony_ci schedule(); 8278c2ecf20Sopenharmony_ci kfree(scsidev); 8288c2ecf20Sopenharmony_ci status = scsicmd->SCp.Status; 8298c2ecf20Sopenharmony_ci kfree(scsicmd); 8308c2ecf20Sopenharmony_ci return status; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci/* Local Structure to set SCSI inquiry data strings */ 8348c2ecf20Sopenharmony_cistruct scsi_inq { 8358c2ecf20Sopenharmony_ci char vid[8]; /* Vendor ID */ 8368c2ecf20Sopenharmony_ci char pid[16]; /* Product ID */ 8378c2ecf20Sopenharmony_ci char prl[4]; /* Product Revision Level */ 8388c2ecf20Sopenharmony_ci}; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/** 8418c2ecf20Sopenharmony_ci * InqStrCopy - string merge 8428c2ecf20Sopenharmony_ci * @a: string to copy from 8438c2ecf20Sopenharmony_ci * @b: string to copy to 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * Copy a String from one location to another 8468c2ecf20Sopenharmony_ci * without copying \0 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic void inqstrcpy(char *a, char *b) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci while (*a != (char)0) 8538c2ecf20Sopenharmony_ci *b++ = *a++; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic char *container_types[] = { 8578c2ecf20Sopenharmony_ci "None", 8588c2ecf20Sopenharmony_ci "Volume", 8598c2ecf20Sopenharmony_ci "Mirror", 8608c2ecf20Sopenharmony_ci "Stripe", 8618c2ecf20Sopenharmony_ci "RAID5", 8628c2ecf20Sopenharmony_ci "SSRW", 8638c2ecf20Sopenharmony_ci "SSRO", 8648c2ecf20Sopenharmony_ci "Morph", 8658c2ecf20Sopenharmony_ci "Legacy", 8668c2ecf20Sopenharmony_ci "RAID4", 8678c2ecf20Sopenharmony_ci "RAID10", 8688c2ecf20Sopenharmony_ci "RAID00", 8698c2ecf20Sopenharmony_ci "V-MIRRORS", 8708c2ecf20Sopenharmony_ci "PSEUDO R4", 8718c2ecf20Sopenharmony_ci "RAID50", 8728c2ecf20Sopenharmony_ci "RAID5D", 8738c2ecf20Sopenharmony_ci "RAID5D0", 8748c2ecf20Sopenharmony_ci "RAID1E", 8758c2ecf20Sopenharmony_ci "RAID6", 8768c2ecf20Sopenharmony_ci "RAID60", 8778c2ecf20Sopenharmony_ci "Unknown" 8788c2ecf20Sopenharmony_ci}; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cichar * get_container_type(unsigned tindex) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci if (tindex >= ARRAY_SIZE(container_types)) 8838c2ecf20Sopenharmony_ci tindex = ARRAY_SIZE(container_types) - 1; 8848c2ecf20Sopenharmony_ci return container_types[tindex]; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci/* Function: setinqstr 8888c2ecf20Sopenharmony_ci * 8898c2ecf20Sopenharmony_ci * Arguments: [1] pointer to void [1] int 8908c2ecf20Sopenharmony_ci * 8918c2ecf20Sopenharmony_ci * Purpose: Sets SCSI inquiry data strings for vendor, product 8928c2ecf20Sopenharmony_ci * and revision level. Allows strings to be set in platform dependent 8938c2ecf20Sopenharmony_ci * files instead of in OS dependent driver source. 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic void setinqstr(struct aac_dev *dev, void *data, int tindex) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct scsi_inq *str; 8998c2ecf20Sopenharmony_ci struct aac_supplement_adapter_info *sup_adap_info; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci sup_adap_info = &dev->supplement_adapter_info; 9028c2ecf20Sopenharmony_ci str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ 9038c2ecf20Sopenharmony_ci memset(str, ' ', sizeof(*str)); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (sup_adap_info->adapter_type_text[0]) { 9068c2ecf20Sopenharmony_ci int c; 9078c2ecf20Sopenharmony_ci char *cp; 9088c2ecf20Sopenharmony_ci char *cname = kmemdup(sup_adap_info->adapter_type_text, 9098c2ecf20Sopenharmony_ci sizeof(sup_adap_info->adapter_type_text), 9108c2ecf20Sopenharmony_ci GFP_ATOMIC); 9118c2ecf20Sopenharmony_ci if (!cname) 9128c2ecf20Sopenharmony_ci return; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci cp = cname; 9158c2ecf20Sopenharmony_ci if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C')) 9168c2ecf20Sopenharmony_ci inqstrcpy("SMC", str->vid); 9178c2ecf20Sopenharmony_ci else { 9188c2ecf20Sopenharmony_ci c = sizeof(str->vid); 9198c2ecf20Sopenharmony_ci while (*cp && *cp != ' ' && --c) 9208c2ecf20Sopenharmony_ci ++cp; 9218c2ecf20Sopenharmony_ci c = *cp; 9228c2ecf20Sopenharmony_ci *cp = '\0'; 9238c2ecf20Sopenharmony_ci inqstrcpy(cname, str->vid); 9248c2ecf20Sopenharmony_ci *cp = c; 9258c2ecf20Sopenharmony_ci while (*cp && *cp != ' ') 9268c2ecf20Sopenharmony_ci ++cp; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci while (*cp == ' ') 9298c2ecf20Sopenharmony_ci ++cp; 9308c2ecf20Sopenharmony_ci /* last six chars reserved for vol type */ 9318c2ecf20Sopenharmony_ci if (strlen(cp) > sizeof(str->pid)) 9328c2ecf20Sopenharmony_ci cp[sizeof(str->pid)] = '\0'; 9338c2ecf20Sopenharmony_ci inqstrcpy (cp, str->pid); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci kfree(cname); 9368c2ecf20Sopenharmony_ci } else { 9378c2ecf20Sopenharmony_ci struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci inqstrcpy (mp->vname, str->vid); 9408c2ecf20Sopenharmony_ci /* last six chars reserved for vol type */ 9418c2ecf20Sopenharmony_ci inqstrcpy (mp->model, str->pid); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (tindex < ARRAY_SIZE(container_types)){ 9458c2ecf20Sopenharmony_ci char *findit = str->pid; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci for ( ; *findit != ' '; findit++); /* walk till we find a space */ 9488c2ecf20Sopenharmony_ci /* RAID is superfluous in the context of a RAID device */ 9498c2ecf20Sopenharmony_ci if (memcmp(findit-4, "RAID", 4) == 0) 9508c2ecf20Sopenharmony_ci *(findit -= 4) = ' '; 9518c2ecf20Sopenharmony_ci if (((findit - str->pid) + strlen(container_types[tindex])) 9528c2ecf20Sopenharmony_ci < (sizeof(str->pid) + sizeof(str->prl))) 9538c2ecf20Sopenharmony_ci inqstrcpy (container_types[tindex], findit + 1); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci inqstrcpy ("V1.0", str->prl); 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic void build_vpd83_type3(struct tvpd_page83 *vpdpage83data, 9598c2ecf20Sopenharmony_ci struct aac_dev *dev, struct scsi_cmnd *scsicmd) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci int container; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci vpdpage83data->type3.codeset = 1; 9648c2ecf20Sopenharmony_ci vpdpage83data->type3.identifiertype = 3; 9658c2ecf20Sopenharmony_ci vpdpage83data->type3.identifierlength = sizeof(vpdpage83data->type3) 9668c2ecf20Sopenharmony_ci - 4; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci for (container = 0; container < dev->maximum_num_containers; 9698c2ecf20Sopenharmony_ci container++) { 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (scmd_id(scsicmd) == container) { 9728c2ecf20Sopenharmony_ci memcpy(vpdpage83data->type3.Identifier, 9738c2ecf20Sopenharmony_ci dev->fsa_dev[container].identifier, 9748c2ecf20Sopenharmony_ci 16); 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic void get_container_serial_callback(void *context, struct fib * fibptr) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci struct aac_get_serial_resp * get_serial_reply; 9838c2ecf20Sopenharmony_ci struct scsi_cmnd * scsicmd; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 9888c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 9898c2ecf20Sopenharmony_ci return; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr); 9928c2ecf20Sopenharmony_ci /* Failure is irrelevant, using default value instead */ 9938c2ecf20Sopenharmony_ci if (le32_to_cpu(get_serial_reply->status) == CT_OK) { 9948c2ecf20Sopenharmony_ci /*Check to see if it's for VPD 0x83 or 0x80 */ 9958c2ecf20Sopenharmony_ci if (scsicmd->cmnd[2] == 0x83) { 9968c2ecf20Sopenharmony_ci /* vpd page 0x83 - Device Identification Page */ 9978c2ecf20Sopenharmony_ci struct aac_dev *dev; 9988c2ecf20Sopenharmony_ci int i; 9998c2ecf20Sopenharmony_ci struct tvpd_page83 vpdpage83data; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci memset(((u8 *)&vpdpage83data), 0, 10048c2ecf20Sopenharmony_ci sizeof(vpdpage83data)); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* DIRECT_ACCESS_DEVIC */ 10078c2ecf20Sopenharmony_ci vpdpage83data.DeviceType = 0; 10088c2ecf20Sopenharmony_ci /* DEVICE_CONNECTED */ 10098c2ecf20Sopenharmony_ci vpdpage83data.DeviceTypeQualifier = 0; 10108c2ecf20Sopenharmony_ci /* VPD_DEVICE_IDENTIFIERS */ 10118c2ecf20Sopenharmony_ci vpdpage83data.PageCode = 0x83; 10128c2ecf20Sopenharmony_ci vpdpage83data.reserved = 0; 10138c2ecf20Sopenharmony_ci vpdpage83data.PageLength = 10148c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type1) + 10158c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type2); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* VPD 83 Type 3 is not supported for ARC */ 10188c2ecf20Sopenharmony_ci if (dev->sa_firmware) 10198c2ecf20Sopenharmony_ci vpdpage83data.PageLength += 10208c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type3); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* T10 Vendor Identifier Field Format */ 10238c2ecf20Sopenharmony_ci /* VpdcodesetAscii */ 10248c2ecf20Sopenharmony_ci vpdpage83data.type1.codeset = 2; 10258c2ecf20Sopenharmony_ci /* VpdIdentifierTypeVendorId */ 10268c2ecf20Sopenharmony_ci vpdpage83data.type1.identifiertype = 1; 10278c2ecf20Sopenharmony_ci vpdpage83data.type1.identifierlength = 10288c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type1) - 4; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* "ADAPTEC " for adaptec */ 10318c2ecf20Sopenharmony_ci memcpy(vpdpage83data.type1.venid, 10328c2ecf20Sopenharmony_ci "ADAPTEC ", 10338c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type1.venid)); 10348c2ecf20Sopenharmony_ci memcpy(vpdpage83data.type1.productid, 10358c2ecf20Sopenharmony_ci "ARRAY ", 10368c2ecf20Sopenharmony_ci sizeof( 10378c2ecf20Sopenharmony_ci vpdpage83data.type1.productid)); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* Convert to ascii based serial number. 10408c2ecf20Sopenharmony_ci * The LSB is the the end. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 10438c2ecf20Sopenharmony_ci u8 temp = 10448c2ecf20Sopenharmony_ci (u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF); 10458c2ecf20Sopenharmony_ci if (temp > 0x9) { 10468c2ecf20Sopenharmony_ci vpdpage83data.type1.serialnumber[i] = 10478c2ecf20Sopenharmony_ci 'A' + (temp - 0xA); 10488c2ecf20Sopenharmony_ci } else { 10498c2ecf20Sopenharmony_ci vpdpage83data.type1.serialnumber[i] = 10508c2ecf20Sopenharmony_ci '0' + temp; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* VpdCodeSetBinary */ 10558c2ecf20Sopenharmony_ci vpdpage83data.type2.codeset = 1; 10568c2ecf20Sopenharmony_ci /* VpdidentifiertypeEUI64 */ 10578c2ecf20Sopenharmony_ci vpdpage83data.type2.identifiertype = 2; 10588c2ecf20Sopenharmony_ci vpdpage83data.type2.identifierlength = 10598c2ecf20Sopenharmony_ci sizeof(vpdpage83data.type2) - 4; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci vpdpage83data.type2.eu64id.venid[0] = 0xD0; 10628c2ecf20Sopenharmony_ci vpdpage83data.type2.eu64id.venid[1] = 0; 10638c2ecf20Sopenharmony_ci vpdpage83data.type2.eu64id.venid[2] = 0; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci vpdpage83data.type2.eu64id.Serial = 10668c2ecf20Sopenharmony_ci get_serial_reply->uid; 10678c2ecf20Sopenharmony_ci vpdpage83data.type2.eu64id.reserved = 0; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* 10708c2ecf20Sopenharmony_ci * VpdIdentifierTypeFCPHName 10718c2ecf20Sopenharmony_ci * VPD 0x83 Type 3 not supported for ARC 10728c2ecf20Sopenharmony_ci */ 10738c2ecf20Sopenharmony_ci if (dev->sa_firmware) { 10748c2ecf20Sopenharmony_ci build_vpd83_type3(&vpdpage83data, 10758c2ecf20Sopenharmony_ci dev, scsicmd); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Move the inquiry data to the response buffer. */ 10798c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &vpdpage83data, 10808c2ecf20Sopenharmony_ci sizeof(vpdpage83data)); 10818c2ecf20Sopenharmony_ci } else { 10828c2ecf20Sopenharmony_ci /* It must be for VPD 0x80 */ 10838c2ecf20Sopenharmony_ci char sp[13]; 10848c2ecf20Sopenharmony_ci /* EVPD bit set */ 10858c2ecf20Sopenharmony_ci sp[0] = INQD_PDT_DA; 10868c2ecf20Sopenharmony_ci sp[1] = scsicmd->cmnd[2]; 10878c2ecf20Sopenharmony_ci sp[2] = 0; 10888c2ecf20Sopenharmony_ci sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", 10898c2ecf20Sopenharmony_ci le32_to_cpu(get_serial_reply->uid)); 10908c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, sp, 10918c2ecf20Sopenharmony_ci sizeof(sp)); 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 10988c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci/* 11028c2ecf20Sopenharmony_ci * aac_get_container_serial - get container serial, none blocking. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_cistatic int aac_get_container_serial(struct scsi_cmnd * scsicmd) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci int status; 11078c2ecf20Sopenharmony_ci struct aac_get_serial *dinfo; 11088c2ecf20Sopenharmony_ci struct fib * cmd_fibcontext; 11098c2ecf20Sopenharmony_ci struct aac_dev * dev; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci aac_fib_init(cmd_fibcontext); 11168c2ecf20Sopenharmony_ci dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci dinfo->command = cpu_to_le32(VM_ContainerConfig); 11198c2ecf20Sopenharmony_ci dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID); 11208c2ecf20Sopenharmony_ci dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); 11218c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 11248c2ecf20Sopenharmony_ci cmd_fibcontext, 11258c2ecf20Sopenharmony_ci sizeof(struct aac_get_serial_resp), 11268c2ecf20Sopenharmony_ci FsaNormal, 11278c2ecf20Sopenharmony_ci 0, 1, 11288c2ecf20Sopenharmony_ci (fib_callback) get_container_serial_callback, 11298c2ecf20Sopenharmony_ci (void *) scsicmd); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* 11328c2ecf20Sopenharmony_ci * Check that the command queued to the controller 11338c2ecf20Sopenharmony_ci */ 11348c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status); 11388c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 11398c2ecf20Sopenharmony_ci return -1; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci/* Function: setinqserial 11438c2ecf20Sopenharmony_ci * 11448c2ecf20Sopenharmony_ci * Arguments: [1] pointer to void [1] int 11458c2ecf20Sopenharmony_ci * 11468c2ecf20Sopenharmony_ci * Purpose: Sets SCSI Unit Serial number. 11478c2ecf20Sopenharmony_ci * This is a fake. We should read a proper 11488c2ecf20Sopenharmony_ci * serial number from the container. <SuSE>But 11498c2ecf20Sopenharmony_ci * without docs it's quite hard to do it :-) 11508c2ecf20Sopenharmony_ci * So this will have to do in the meantime.</SuSE> 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int setinqserial(struct aac_dev *dev, void *data, int cid) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * This breaks array migration. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X", 11598c2ecf20Sopenharmony_ci le32_to_cpu(dev->adapter_info.serial[0]), cid); 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic inline void set_sense(struct sense_data *sense_data, u8 sense_key, 11638c2ecf20Sopenharmony_ci u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci u8 *sense_buf = (u8 *)sense_data; 11668c2ecf20Sopenharmony_ci /* Sense data valid, err code 70h */ 11678c2ecf20Sopenharmony_ci sense_buf[0] = 0x70; /* No info field */ 11688c2ecf20Sopenharmony_ci sense_buf[1] = 0; /* Segment number, always zero */ 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci sense_buf[2] = sense_key; /* Sense key */ 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci sense_buf[12] = sense_code; /* Additional sense code */ 11738c2ecf20Sopenharmony_ci sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (sense_key == ILLEGAL_REQUEST) { 11768c2ecf20Sopenharmony_ci sense_buf[7] = 10; /* Additional sense length */ 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci sense_buf[15] = bit_pointer; 11798c2ecf20Sopenharmony_ci /* Illegal parameter is in the parameter block */ 11808c2ecf20Sopenharmony_ci if (sense_code == SENCODE_INVALID_CDB_FIELD) 11818c2ecf20Sopenharmony_ci sense_buf[15] |= 0xc0;/* Std sense key specific field */ 11828c2ecf20Sopenharmony_ci /* Illegal parameter is in the CDB block */ 11838c2ecf20Sopenharmony_ci sense_buf[16] = field_pointer >> 8; /* MSB */ 11848c2ecf20Sopenharmony_ci sense_buf[17] = field_pointer; /* LSB */ 11858c2ecf20Sopenharmony_ci } else 11868c2ecf20Sopenharmony_ci sense_buf[7] = 6; /* Additional sense length */ 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci if (lba & 0xffffffff00000000LL) { 11928c2ecf20Sopenharmony_ci int cid = scmd_id(cmd); 11938c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 11948c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 11958c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 11968c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 11978c2ecf20Sopenharmony_ci HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 11988c2ecf20Sopenharmony_ci ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 11998c2ecf20Sopenharmony_ci memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 12008c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 12018c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 12028c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 12038c2ecf20Sopenharmony_ci return 1; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci return 0; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci return 0; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic void io_callback(void *context, struct fib * fibptr); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 12188c2ecf20Sopenharmony_ci u16 fibsize, command; 12198c2ecf20Sopenharmony_ci long ret; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci aac_fib_init(fib); 12228c2ecf20Sopenharmony_ci if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 12238c2ecf20Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && 12248c2ecf20Sopenharmony_ci !dev->sync_mode) { 12258c2ecf20Sopenharmony_ci struct aac_raw_io2 *readcmd2; 12268c2ecf20Sopenharmony_ci readcmd2 = (struct aac_raw_io2 *) fib_data(fib); 12278c2ecf20Sopenharmony_ci memset(readcmd2, 0, sizeof(struct aac_raw_io2)); 12288c2ecf20Sopenharmony_ci readcmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff)); 12298c2ecf20Sopenharmony_ci readcmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 12308c2ecf20Sopenharmony_ci readcmd2->byteCount = cpu_to_le32(count * 12318c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 12328c2ecf20Sopenharmony_ci readcmd2->cid = cpu_to_le16(scmd_id(cmd)); 12338c2ecf20Sopenharmony_ci readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ); 12348c2ecf20Sopenharmony_ci ret = aac_build_sgraw2(cmd, readcmd2, 12358c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize); 12368c2ecf20Sopenharmony_ci if (ret < 0) 12378c2ecf20Sopenharmony_ci return ret; 12388c2ecf20Sopenharmony_ci command = ContainerRawIo2; 12398c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_raw_io2) + 12408c2ecf20Sopenharmony_ci ((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212)); 12418c2ecf20Sopenharmony_ci } else { 12428c2ecf20Sopenharmony_ci struct aac_raw_io *readcmd; 12438c2ecf20Sopenharmony_ci readcmd = (struct aac_raw_io *) fib_data(fib); 12448c2ecf20Sopenharmony_ci readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); 12458c2ecf20Sopenharmony_ci readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 12468c2ecf20Sopenharmony_ci readcmd->count = cpu_to_le32(count * 12478c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 12488c2ecf20Sopenharmony_ci readcmd->cid = cpu_to_le16(scmd_id(cmd)); 12498c2ecf20Sopenharmony_ci readcmd->flags = cpu_to_le16(RIO_TYPE_READ); 12508c2ecf20Sopenharmony_ci readcmd->bpTotal = 0; 12518c2ecf20Sopenharmony_ci readcmd->bpComplete = 0; 12528c2ecf20Sopenharmony_ci ret = aac_build_sgraw(cmd, &readcmd->sg); 12538c2ecf20Sopenharmony_ci if (ret < 0) 12548c2ecf20Sopenharmony_ci return ret; 12558c2ecf20Sopenharmony_ci command = ContainerRawIo; 12568c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_raw_io) + 12578c2ecf20Sopenharmony_ci ((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw)); 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); 12618c2ecf20Sopenharmony_ci /* 12628c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci return aac_fib_send(command, 12658c2ecf20Sopenharmony_ci fib, 12668c2ecf20Sopenharmony_ci fibsize, 12678c2ecf20Sopenharmony_ci FsaNormal, 12688c2ecf20Sopenharmony_ci 0, 1, 12698c2ecf20Sopenharmony_ci (fib_callback) io_callback, 12708c2ecf20Sopenharmony_ci (void *) cmd); 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci u16 fibsize; 12768c2ecf20Sopenharmony_ci struct aac_read64 *readcmd; 12778c2ecf20Sopenharmony_ci long ret; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci aac_fib_init(fib); 12808c2ecf20Sopenharmony_ci readcmd = (struct aac_read64 *) fib_data(fib); 12818c2ecf20Sopenharmony_ci readcmd->command = cpu_to_le32(VM_CtHostRead64); 12828c2ecf20Sopenharmony_ci readcmd->cid = cpu_to_le16(scmd_id(cmd)); 12838c2ecf20Sopenharmony_ci readcmd->sector_count = cpu_to_le16(count); 12848c2ecf20Sopenharmony_ci readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 12858c2ecf20Sopenharmony_ci readcmd->pad = 0; 12868c2ecf20Sopenharmony_ci readcmd->flags = 0; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci ret = aac_build_sg64(cmd, &readcmd->sg); 12898c2ecf20Sopenharmony_ci if (ret < 0) 12908c2ecf20Sopenharmony_ci return ret; 12918c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_read64) + 12928c2ecf20Sopenharmony_ci ((le32_to_cpu(readcmd->sg.count) - 1) * 12938c2ecf20Sopenharmony_ci sizeof (struct sgentry64)); 12948c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 12958c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ci return aac_fib_send(ContainerCommand64, 13008c2ecf20Sopenharmony_ci fib, 13018c2ecf20Sopenharmony_ci fibsize, 13028c2ecf20Sopenharmony_ci FsaNormal, 13038c2ecf20Sopenharmony_ci 0, 1, 13048c2ecf20Sopenharmony_ci (fib_callback) io_callback, 13058c2ecf20Sopenharmony_ci (void *) cmd); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci u16 fibsize; 13118c2ecf20Sopenharmony_ci struct aac_read *readcmd; 13128c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 13138c2ecf20Sopenharmony_ci long ret; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci aac_fib_init(fib); 13168c2ecf20Sopenharmony_ci readcmd = (struct aac_read *) fib_data(fib); 13178c2ecf20Sopenharmony_ci readcmd->command = cpu_to_le32(VM_CtBlockRead); 13188c2ecf20Sopenharmony_ci readcmd->cid = cpu_to_le32(scmd_id(cmd)); 13198c2ecf20Sopenharmony_ci readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 13208c2ecf20Sopenharmony_ci readcmd->count = cpu_to_le32(count * 13218c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci ret = aac_build_sg(cmd, &readcmd->sg); 13248c2ecf20Sopenharmony_ci if (ret < 0) 13258c2ecf20Sopenharmony_ci return ret; 13268c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_read) + 13278c2ecf20Sopenharmony_ci ((le32_to_cpu(readcmd->sg.count) - 1) * 13288c2ecf20Sopenharmony_ci sizeof (struct sgentry)); 13298c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 13308c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 13318c2ecf20Sopenharmony_ci /* 13328c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 13338c2ecf20Sopenharmony_ci */ 13348c2ecf20Sopenharmony_ci return aac_fib_send(ContainerCommand, 13358c2ecf20Sopenharmony_ci fib, 13368c2ecf20Sopenharmony_ci fibsize, 13378c2ecf20Sopenharmony_ci FsaNormal, 13388c2ecf20Sopenharmony_ci 0, 1, 13398c2ecf20Sopenharmony_ci (fib_callback) io_callback, 13408c2ecf20Sopenharmony_ci (void *) cmd); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 13468c2ecf20Sopenharmony_ci u16 fibsize, command; 13478c2ecf20Sopenharmony_ci long ret; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci aac_fib_init(fib); 13508c2ecf20Sopenharmony_ci if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 13518c2ecf20Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && 13528c2ecf20Sopenharmony_ci !dev->sync_mode) { 13538c2ecf20Sopenharmony_ci struct aac_raw_io2 *writecmd2; 13548c2ecf20Sopenharmony_ci writecmd2 = (struct aac_raw_io2 *) fib_data(fib); 13558c2ecf20Sopenharmony_ci memset(writecmd2, 0, sizeof(struct aac_raw_io2)); 13568c2ecf20Sopenharmony_ci writecmd2->blockLow = cpu_to_le32((u32)(lba&0xffffffff)); 13578c2ecf20Sopenharmony_ci writecmd2->blockHigh = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 13588c2ecf20Sopenharmony_ci writecmd2->byteCount = cpu_to_le32(count * 13598c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 13608c2ecf20Sopenharmony_ci writecmd2->cid = cpu_to_le16(scmd_id(cmd)); 13618c2ecf20Sopenharmony_ci writecmd2->flags = (fua && ((aac_cache & 5) != 1) && 13628c2ecf20Sopenharmony_ci (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? 13638c2ecf20Sopenharmony_ci cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) : 13648c2ecf20Sopenharmony_ci cpu_to_le16(RIO2_IO_TYPE_WRITE); 13658c2ecf20Sopenharmony_ci ret = aac_build_sgraw2(cmd, writecmd2, 13668c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize); 13678c2ecf20Sopenharmony_ci if (ret < 0) 13688c2ecf20Sopenharmony_ci return ret; 13698c2ecf20Sopenharmony_ci command = ContainerRawIo2; 13708c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_raw_io2) + 13718c2ecf20Sopenharmony_ci ((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212)); 13728c2ecf20Sopenharmony_ci } else { 13738c2ecf20Sopenharmony_ci struct aac_raw_io *writecmd; 13748c2ecf20Sopenharmony_ci writecmd = (struct aac_raw_io *) fib_data(fib); 13758c2ecf20Sopenharmony_ci writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); 13768c2ecf20Sopenharmony_ci writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); 13778c2ecf20Sopenharmony_ci writecmd->count = cpu_to_le32(count * 13788c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 13798c2ecf20Sopenharmony_ci writecmd->cid = cpu_to_le16(scmd_id(cmd)); 13808c2ecf20Sopenharmony_ci writecmd->flags = (fua && ((aac_cache & 5) != 1) && 13818c2ecf20Sopenharmony_ci (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? 13828c2ecf20Sopenharmony_ci cpu_to_le16(RIO_TYPE_WRITE|RIO_SUREWRITE) : 13838c2ecf20Sopenharmony_ci cpu_to_le16(RIO_TYPE_WRITE); 13848c2ecf20Sopenharmony_ci writecmd->bpTotal = 0; 13858c2ecf20Sopenharmony_ci writecmd->bpComplete = 0; 13868c2ecf20Sopenharmony_ci ret = aac_build_sgraw(cmd, &writecmd->sg); 13878c2ecf20Sopenharmony_ci if (ret < 0) 13888c2ecf20Sopenharmony_ci return ret; 13898c2ecf20Sopenharmony_ci command = ContainerRawIo; 13908c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_raw_io) + 13918c2ecf20Sopenharmony_ci ((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw)); 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); 13958c2ecf20Sopenharmony_ci /* 13968c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 13978c2ecf20Sopenharmony_ci */ 13988c2ecf20Sopenharmony_ci return aac_fib_send(command, 13998c2ecf20Sopenharmony_ci fib, 14008c2ecf20Sopenharmony_ci fibsize, 14018c2ecf20Sopenharmony_ci FsaNormal, 14028c2ecf20Sopenharmony_ci 0, 1, 14038c2ecf20Sopenharmony_ci (fib_callback) io_callback, 14048c2ecf20Sopenharmony_ci (void *) cmd); 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci u16 fibsize; 14108c2ecf20Sopenharmony_ci struct aac_write64 *writecmd; 14118c2ecf20Sopenharmony_ci long ret; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci aac_fib_init(fib); 14148c2ecf20Sopenharmony_ci writecmd = (struct aac_write64 *) fib_data(fib); 14158c2ecf20Sopenharmony_ci writecmd->command = cpu_to_le32(VM_CtHostWrite64); 14168c2ecf20Sopenharmony_ci writecmd->cid = cpu_to_le16(scmd_id(cmd)); 14178c2ecf20Sopenharmony_ci writecmd->sector_count = cpu_to_le16(count); 14188c2ecf20Sopenharmony_ci writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 14198c2ecf20Sopenharmony_ci writecmd->pad = 0; 14208c2ecf20Sopenharmony_ci writecmd->flags = 0; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci ret = aac_build_sg64(cmd, &writecmd->sg); 14238c2ecf20Sopenharmony_ci if (ret < 0) 14248c2ecf20Sopenharmony_ci return ret; 14258c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_write64) + 14268c2ecf20Sopenharmony_ci ((le32_to_cpu(writecmd->sg.count) - 1) * 14278c2ecf20Sopenharmony_ci sizeof (struct sgentry64)); 14288c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 14298c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 14308c2ecf20Sopenharmony_ci /* 14318c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci return aac_fib_send(ContainerCommand64, 14348c2ecf20Sopenharmony_ci fib, 14358c2ecf20Sopenharmony_ci fibsize, 14368c2ecf20Sopenharmony_ci FsaNormal, 14378c2ecf20Sopenharmony_ci 0, 1, 14388c2ecf20Sopenharmony_ci (fib_callback) io_callback, 14398c2ecf20Sopenharmony_ci (void *) cmd); 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cistatic int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci u16 fibsize; 14458c2ecf20Sopenharmony_ci struct aac_write *writecmd; 14468c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 14478c2ecf20Sopenharmony_ci long ret; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci aac_fib_init(fib); 14508c2ecf20Sopenharmony_ci writecmd = (struct aac_write *) fib_data(fib); 14518c2ecf20Sopenharmony_ci writecmd->command = cpu_to_le32(VM_CtBlockWrite); 14528c2ecf20Sopenharmony_ci writecmd->cid = cpu_to_le32(scmd_id(cmd)); 14538c2ecf20Sopenharmony_ci writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); 14548c2ecf20Sopenharmony_ci writecmd->count = cpu_to_le32(count * 14558c2ecf20Sopenharmony_ci dev->fsa_dev[scmd_id(cmd)].block_size); 14568c2ecf20Sopenharmony_ci writecmd->sg.count = cpu_to_le32(1); 14578c2ecf20Sopenharmony_ci /* ->stable is not used - it did mean which type of write */ 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci ret = aac_build_sg(cmd, &writecmd->sg); 14608c2ecf20Sopenharmony_ci if (ret < 0) 14618c2ecf20Sopenharmony_ci return ret; 14628c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_write) + 14638c2ecf20Sopenharmony_ci ((le32_to_cpu(writecmd->sg.count) - 1) * 14648c2ecf20Sopenharmony_ci sizeof (struct sgentry)); 14658c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 14668c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 14678c2ecf20Sopenharmony_ci /* 14688c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci return aac_fib_send(ContainerCommand, 14718c2ecf20Sopenharmony_ci fib, 14728c2ecf20Sopenharmony_ci fibsize, 14738c2ecf20Sopenharmony_ci FsaNormal, 14748c2ecf20Sopenharmony_ci 0, 1, 14758c2ecf20Sopenharmony_ci (fib_callback) io_callback, 14768c2ecf20Sopenharmony_ci (void *) cmd); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci struct aac_srb * srbcmd; 14828c2ecf20Sopenharmony_ci u32 flag; 14838c2ecf20Sopenharmony_ci u32 timeout; 14848c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci aac_fib_init(fib); 14878c2ecf20Sopenharmony_ci switch(cmd->sc_data_direction){ 14888c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 14898c2ecf20Sopenharmony_ci flag = SRB_DataOut; 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 14928c2ecf20Sopenharmony_ci flag = SRB_DataIn | SRB_DataOut; 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 14958c2ecf20Sopenharmony_ci flag = SRB_DataIn; 14968c2ecf20Sopenharmony_ci break; 14978c2ecf20Sopenharmony_ci case DMA_NONE: 14988c2ecf20Sopenharmony_ci default: /* shuts up some versions of gcc */ 14998c2ecf20Sopenharmony_ci flag = SRB_NoDataXfer; 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci srbcmd = (struct aac_srb*) fib_data(fib); 15048c2ecf20Sopenharmony_ci srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); 15058c2ecf20Sopenharmony_ci srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd))); 15068c2ecf20Sopenharmony_ci srbcmd->id = cpu_to_le32(scmd_id(cmd)); 15078c2ecf20Sopenharmony_ci srbcmd->lun = cpu_to_le32(cmd->device->lun); 15088c2ecf20Sopenharmony_ci srbcmd->flags = cpu_to_le32(flag); 15098c2ecf20Sopenharmony_ci timeout = cmd->request->timeout/HZ; 15108c2ecf20Sopenharmony_ci if (timeout == 0) 15118c2ecf20Sopenharmony_ci timeout = (dev->sa_firmware ? AAC_SA_TIMEOUT : AAC_ARC_TIMEOUT); 15128c2ecf20Sopenharmony_ci srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds 15138c2ecf20Sopenharmony_ci srbcmd->retry_limit = 0; /* Obsolete parameter */ 15148c2ecf20Sopenharmony_ci srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len); 15158c2ecf20Sopenharmony_ci return srbcmd; 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic struct aac_hba_cmd_req *aac_construct_hbacmd(struct fib *fib, 15198c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci struct aac_hba_cmd_req *hbacmd; 15228c2ecf20Sopenharmony_ci struct aac_dev *dev; 15238c2ecf20Sopenharmony_ci int bus, target; 15248c2ecf20Sopenharmony_ci u64 address; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci dev = (struct aac_dev *)cmd->device->host->hostdata; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci hbacmd = (struct aac_hba_cmd_req *)fib->hw_fib_va; 15298c2ecf20Sopenharmony_ci memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ 15308c2ecf20Sopenharmony_ci /* iu_type is a parameter of aac_hba_send */ 15318c2ecf20Sopenharmony_ci switch (cmd->sc_data_direction) { 15328c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 15338c2ecf20Sopenharmony_ci hbacmd->byte1 = 2; 15348c2ecf20Sopenharmony_ci break; 15358c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 15368c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 15378c2ecf20Sopenharmony_ci hbacmd->byte1 = 1; 15388c2ecf20Sopenharmony_ci break; 15398c2ecf20Sopenharmony_ci case DMA_NONE: 15408c2ecf20Sopenharmony_ci default: 15418c2ecf20Sopenharmony_ci break; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci hbacmd->lun[1] = cpu_to_le32(cmd->device->lun); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci bus = aac_logical_to_phys(scmd_channel(cmd)); 15468c2ecf20Sopenharmony_ci target = scmd_id(cmd); 15478c2ecf20Sopenharmony_ci hbacmd->it_nexus = dev->hba_map[bus][target].rmw_nexus; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* we fill in reply_qid later in aac_src_deliver_message */ 15508c2ecf20Sopenharmony_ci /* we fill in iu_type, request_id later in aac_hba_send */ 15518c2ecf20Sopenharmony_ci /* we fill in emb_data_desc_count later in aac_build_sghba */ 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci memcpy(hbacmd->cdb, cmd->cmnd, cmd->cmd_len); 15548c2ecf20Sopenharmony_ci hbacmd->data_length = cpu_to_le32(scsi_bufflen(cmd)); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci address = (u64)fib->hw_error_pa; 15578c2ecf20Sopenharmony_ci hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); 15588c2ecf20Sopenharmony_ci hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); 15598c2ecf20Sopenharmony_ci hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci return hbacmd; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic void aac_srb_callback(void *context, struct fib * fibptr); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci u16 fibsize; 15698c2ecf20Sopenharmony_ci struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); 15708c2ecf20Sopenharmony_ci long ret; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg); 15738c2ecf20Sopenharmony_ci if (ret < 0) 15748c2ecf20Sopenharmony_ci return ret; 15758c2ecf20Sopenharmony_ci srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 15788c2ecf20Sopenharmony_ci memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); 15798c2ecf20Sopenharmony_ci /* 15808c2ecf20Sopenharmony_ci * Build Scatter/Gather list 15818c2ecf20Sopenharmony_ci */ 15828c2ecf20Sopenharmony_ci fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + 15838c2ecf20Sopenharmony_ci ((le32_to_cpu(srbcmd->sg.count) & 0xff) * 15848c2ecf20Sopenharmony_ci sizeof (struct sgentry64)); 15858c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 15868c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* 15898c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 15908c2ecf20Sopenharmony_ci */ 15918c2ecf20Sopenharmony_ci return aac_fib_send(ScsiPortCommand64, fib, 15928c2ecf20Sopenharmony_ci fibsize, FsaNormal, 0, 1, 15938c2ecf20Sopenharmony_ci (fib_callback) aac_srb_callback, 15948c2ecf20Sopenharmony_ci (void *) cmd); 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) 15988c2ecf20Sopenharmony_ci{ 15998c2ecf20Sopenharmony_ci u16 fibsize; 16008c2ecf20Sopenharmony_ci struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); 16018c2ecf20Sopenharmony_ci long ret; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg); 16048c2ecf20Sopenharmony_ci if (ret < 0) 16058c2ecf20Sopenharmony_ci return ret; 16068c2ecf20Sopenharmony_ci srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); 16098c2ecf20Sopenharmony_ci memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); 16108c2ecf20Sopenharmony_ci /* 16118c2ecf20Sopenharmony_ci * Build Scatter/Gather list 16128c2ecf20Sopenharmony_ci */ 16138c2ecf20Sopenharmony_ci fibsize = sizeof (struct aac_srb) + 16148c2ecf20Sopenharmony_ci (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 16158c2ecf20Sopenharmony_ci sizeof (struct sgentry)); 16168c2ecf20Sopenharmony_ci BUG_ON (fibsize > (fib->dev->max_fib_size - 16178c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr))); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* 16208c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 16218c2ecf20Sopenharmony_ci */ 16228c2ecf20Sopenharmony_ci return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1, 16238c2ecf20Sopenharmony_ci (fib_callback) aac_srb_callback, (void *) cmd); 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac && 16298c2ecf20Sopenharmony_ci (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) 16308c2ecf20Sopenharmony_ci return FAILED; 16318c2ecf20Sopenharmony_ci return aac_scsi_32(fib, cmd); 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_cistatic int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd); 16378c2ecf20Sopenharmony_ci struct aac_dev *dev; 16388c2ecf20Sopenharmony_ci long ret; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci dev = (struct aac_dev *)cmd->device->host->hostdata; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci ret = aac_build_sghba(cmd, hbacmd, 16438c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize, (u64)fib->hw_sgl_pa); 16448c2ecf20Sopenharmony_ci if (ret < 0) 16458c2ecf20Sopenharmony_ci return ret; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* 16488c2ecf20Sopenharmony_ci * Now send the HBA command to the adapter 16498c2ecf20Sopenharmony_ci */ 16508c2ecf20Sopenharmony_ci fib->hbacmd_size = 64 + le32_to_cpu(hbacmd->emb_data_desc_count) * 16518c2ecf20Sopenharmony_ci sizeof(struct aac_hba_sgl); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci return aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, fib, 16548c2ecf20Sopenharmony_ci (fib_callback) aac_hba_callback, 16558c2ecf20Sopenharmony_ci (void *) cmd); 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic int aac_send_safw_bmic_cmd(struct aac_dev *dev, 16598c2ecf20Sopenharmony_ci struct aac_srb_unit *srbu, void *xfer_buf, int xfer_len) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci struct fib *fibptr; 16628c2ecf20Sopenharmony_ci dma_addr_t addr; 16638c2ecf20Sopenharmony_ci int rcode; 16648c2ecf20Sopenharmony_ci int fibsize; 16658c2ecf20Sopenharmony_ci struct aac_srb *srb; 16668c2ecf20Sopenharmony_ci struct aac_srb_reply *srb_reply; 16678c2ecf20Sopenharmony_ci struct sgmap64 *sg64; 16688c2ecf20Sopenharmony_ci u32 vbus; 16698c2ecf20Sopenharmony_ci u32 vid; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (!dev->sa_firmware) 16728c2ecf20Sopenharmony_ci return 0; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* allocate FIB */ 16758c2ecf20Sopenharmony_ci fibptr = aac_fib_alloc(dev); 16768c2ecf20Sopenharmony_ci if (!fibptr) 16778c2ecf20Sopenharmony_ci return -ENOMEM; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 16808c2ecf20Sopenharmony_ci fibptr->hw_fib_va->header.XferState &= 16818c2ecf20Sopenharmony_ci ~cpu_to_le32(FastResponseCapable); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + 16848c2ecf20Sopenharmony_ci sizeof(struct sgentry64); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* allocate DMA buffer for response */ 16878c2ecf20Sopenharmony_ci addr = dma_map_single(&dev->pdev->dev, xfer_buf, xfer_len, 16888c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 16898c2ecf20Sopenharmony_ci if (dma_mapping_error(&dev->pdev->dev, addr)) { 16908c2ecf20Sopenharmony_ci rcode = -ENOMEM; 16918c2ecf20Sopenharmony_ci goto fib_error; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci srb = fib_data(fibptr); 16958c2ecf20Sopenharmony_ci memcpy(srb, &srbu->srb, sizeof(struct aac_srb)); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci vbus = (u32)le16_to_cpu( 16988c2ecf20Sopenharmony_ci dev->supplement_adapter_info.virt_device_bus); 16998c2ecf20Sopenharmony_ci vid = (u32)le16_to_cpu( 17008c2ecf20Sopenharmony_ci dev->supplement_adapter_info.virt_device_target); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* set the common request fields */ 17038c2ecf20Sopenharmony_ci srb->channel = cpu_to_le32(vbus); 17048c2ecf20Sopenharmony_ci srb->id = cpu_to_le32(vid); 17058c2ecf20Sopenharmony_ci srb->lun = 0; 17068c2ecf20Sopenharmony_ci srb->function = cpu_to_le32(SRBF_ExecuteScsi); 17078c2ecf20Sopenharmony_ci srb->timeout = 0; 17088c2ecf20Sopenharmony_ci srb->retry_limit = 0; 17098c2ecf20Sopenharmony_ci srb->cdb_size = cpu_to_le32(16); 17108c2ecf20Sopenharmony_ci srb->count = cpu_to_le32(xfer_len); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci sg64 = (struct sgmap64 *)&srb->sg; 17138c2ecf20Sopenharmony_ci sg64->count = cpu_to_le32(1); 17148c2ecf20Sopenharmony_ci sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr)); 17158c2ecf20Sopenharmony_ci sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr)); 17168c2ecf20Sopenharmony_ci sg64->sg[0].count = cpu_to_le32(xfer_len); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci /* 17198c2ecf20Sopenharmony_ci * Copy the updated data for other dumping or other usage if needed 17208c2ecf20Sopenharmony_ci */ 17218c2ecf20Sopenharmony_ci memcpy(&srbu->srb, srb, sizeof(struct aac_srb)); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci /* issue request to the controller */ 17248c2ecf20Sopenharmony_ci rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize, FsaNormal, 17258c2ecf20Sopenharmony_ci 1, 1, NULL, NULL); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (rcode == -ERESTARTSYS) 17288c2ecf20Sopenharmony_ci rcode = -ERESTART; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 17318c2ecf20Sopenharmony_ci goto bmic_error; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci srb_reply = (struct aac_srb_reply *)fib_data(fibptr); 17348c2ecf20Sopenharmony_ci memcpy(&srbu->srb_reply, srb_reply, sizeof(struct aac_srb_reply)); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cibmic_error: 17378c2ecf20Sopenharmony_ci dma_unmap_single(&dev->pdev->dev, addr, xfer_len, DMA_BIDIRECTIONAL); 17388c2ecf20Sopenharmony_cifib_error: 17398c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 17408c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 17418c2ecf20Sopenharmony_ci return rcode; 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic void aac_set_safw_target_qd(struct aac_dev *dev, int bus, int target) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci struct aac_ciss_identify_pd *identify_resp; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (dev->hba_map[bus][target].devtype != AAC_DEVTYPE_NATIVE_RAW) 17508c2ecf20Sopenharmony_ci return; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci identify_resp = dev->hba_map[bus][target].safw_identify_resp; 17538c2ecf20Sopenharmony_ci if (identify_resp == NULL) { 17548c2ecf20Sopenharmony_ci dev->hba_map[bus][target].qd_limit = 32; 17558c2ecf20Sopenharmony_ci return; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci if (identify_resp->current_queue_depth_limit <= 0 || 17598c2ecf20Sopenharmony_ci identify_resp->current_queue_depth_limit > 255) 17608c2ecf20Sopenharmony_ci dev->hba_map[bus][target].qd_limit = 32; 17618c2ecf20Sopenharmony_ci else 17628c2ecf20Sopenharmony_ci dev->hba_map[bus][target].qd_limit = 17638c2ecf20Sopenharmony_ci identify_resp->current_queue_depth_limit; 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cistatic int aac_issue_safw_bmic_identify(struct aac_dev *dev, 17678c2ecf20Sopenharmony_ci struct aac_ciss_identify_pd **identify_resp, u32 bus, u32 target) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci int rcode = -ENOMEM; 17708c2ecf20Sopenharmony_ci int datasize; 17718c2ecf20Sopenharmony_ci struct aac_srb_unit srbu; 17728c2ecf20Sopenharmony_ci struct aac_srb *srbcmd; 17738c2ecf20Sopenharmony_ci struct aac_ciss_identify_pd *identify_reply; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci datasize = sizeof(struct aac_ciss_identify_pd); 17768c2ecf20Sopenharmony_ci identify_reply = kmalloc(datasize, GFP_KERNEL); 17778c2ecf20Sopenharmony_ci if (!identify_reply) 17788c2ecf20Sopenharmony_ci goto out; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci memset(&srbu, 0, sizeof(struct aac_srb_unit)); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci srbcmd = &srbu.srb; 17838c2ecf20Sopenharmony_ci srbcmd->flags = cpu_to_le32(SRB_DataIn); 17848c2ecf20Sopenharmony_ci srbcmd->cdb[0] = 0x26; 17858c2ecf20Sopenharmony_ci srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF); 17868c2ecf20Sopenharmony_ci srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci rcode = aac_send_safw_bmic_cmd(dev, &srbu, identify_reply, datasize); 17898c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 17908c2ecf20Sopenharmony_ci goto mem_free_all; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci *identify_resp = identify_reply; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ciout: 17958c2ecf20Sopenharmony_ci return rcode; 17968c2ecf20Sopenharmony_cimem_free_all: 17978c2ecf20Sopenharmony_ci kfree(identify_reply); 17988c2ecf20Sopenharmony_ci goto out; 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic inline void aac_free_safw_ciss_luns(struct aac_dev *dev) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci kfree(dev->safw_phys_luns); 18048c2ecf20Sopenharmony_ci dev->safw_phys_luns = NULL; 18058c2ecf20Sopenharmony_ci} 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci/** 18088c2ecf20Sopenharmony_ci * aac_get_safw_ciss_luns() Process topology change 18098c2ecf20Sopenharmony_ci * @dev: aac_dev structure 18108c2ecf20Sopenharmony_ci * 18118c2ecf20Sopenharmony_ci * Execute a CISS REPORT PHYS LUNS and process the results into 18128c2ecf20Sopenharmony_ci * the current hba_map. 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_cistatic int aac_get_safw_ciss_luns(struct aac_dev *dev) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci int rcode = -ENOMEM; 18178c2ecf20Sopenharmony_ci int datasize; 18188c2ecf20Sopenharmony_ci struct aac_srb *srbcmd; 18198c2ecf20Sopenharmony_ci struct aac_srb_unit srbu; 18208c2ecf20Sopenharmony_ci struct aac_ciss_phys_luns_resp *phys_luns; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci datasize = sizeof(struct aac_ciss_phys_luns_resp) + 18238c2ecf20Sopenharmony_ci (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); 18248c2ecf20Sopenharmony_ci phys_luns = kmalloc(datasize, GFP_KERNEL); 18258c2ecf20Sopenharmony_ci if (phys_luns == NULL) 18268c2ecf20Sopenharmony_ci goto out; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci memset(&srbu, 0, sizeof(struct aac_srb_unit)); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci srbcmd = &srbu.srb; 18318c2ecf20Sopenharmony_ci srbcmd->flags = cpu_to_le32(SRB_DataIn); 18328c2ecf20Sopenharmony_ci srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS; 18338c2ecf20Sopenharmony_ci srbcmd->cdb[1] = 2; /* extended reporting */ 18348c2ecf20Sopenharmony_ci srbcmd->cdb[8] = (u8)(datasize >> 8); 18358c2ecf20Sopenharmony_ci srbcmd->cdb[9] = (u8)(datasize); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci rcode = aac_send_safw_bmic_cmd(dev, &srbu, phys_luns, datasize); 18388c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 18398c2ecf20Sopenharmony_ci goto mem_free_all; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (phys_luns->resp_flag != 2) { 18428c2ecf20Sopenharmony_ci rcode = -ENOMSG; 18438c2ecf20Sopenharmony_ci goto mem_free_all; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci dev->safw_phys_luns = phys_luns; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ciout: 18498c2ecf20Sopenharmony_ci return rcode; 18508c2ecf20Sopenharmony_cimem_free_all: 18518c2ecf20Sopenharmony_ci kfree(phys_luns); 18528c2ecf20Sopenharmony_ci goto out; 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_lun_count(struct aac_dev *dev) 18568c2ecf20Sopenharmony_ci{ 18578c2ecf20Sopenharmony_ci return get_unaligned_be32(&dev->safw_phys_luns->list_length[0])/24; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_bus(struct aac_dev *dev, int lun) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci return dev->safw_phys_luns->lun[lun].level2[1] & 0x3f; 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_target(struct aac_dev *dev, int lun) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci return dev->safw_phys_luns->lun[lun].level2[0]; 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_expose_flag(struct aac_dev *dev, int lun) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci return dev->safw_phys_luns->lun[lun].bus >> 6; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_attribs(struct aac_dev *dev, int lun) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci return dev->safw_phys_luns->lun[lun].node_ident[9]; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_nexus(struct aac_dev *dev, int lun) 18818c2ecf20Sopenharmony_ci{ 18828c2ecf20Sopenharmony_ci return *((u32 *)&dev->safw_phys_luns->lun[lun].node_ident[12]); 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_cistatic inline u32 aac_get_safw_phys_device_type(struct aac_dev *dev, int lun) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci return dev->safw_phys_luns->lun[lun].node_ident[8]; 18888c2ecf20Sopenharmony_ci} 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cistatic inline void aac_free_safw_identify_resp(struct aac_dev *dev, 18918c2ecf20Sopenharmony_ci int bus, int target) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci kfree(dev->hba_map[bus][target].safw_identify_resp); 18948c2ecf20Sopenharmony_ci dev->hba_map[bus][target].safw_identify_resp = NULL; 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_cistatic inline void aac_free_safw_all_identify_resp(struct aac_dev *dev, 18988c2ecf20Sopenharmony_ci int lun_count) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci int luns; 19018c2ecf20Sopenharmony_ci int i; 19028c2ecf20Sopenharmony_ci u32 bus; 19038c2ecf20Sopenharmony_ci u32 target; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci luns = aac_get_safw_phys_lun_count(dev); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (luns < lun_count) 19088c2ecf20Sopenharmony_ci lun_count = luns; 19098c2ecf20Sopenharmony_ci else if (lun_count < 0) 19108c2ecf20Sopenharmony_ci lun_count = luns; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci for (i = 0; i < lun_count; i++) { 19138c2ecf20Sopenharmony_ci bus = aac_get_safw_phys_bus(dev, i); 19148c2ecf20Sopenharmony_ci target = aac_get_safw_phys_target(dev, i); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci aac_free_safw_identify_resp(dev, bus, target); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_cistatic int aac_get_safw_attr_all_targets(struct aac_dev *dev) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci int i; 19238c2ecf20Sopenharmony_ci int rcode = 0; 19248c2ecf20Sopenharmony_ci u32 lun_count; 19258c2ecf20Sopenharmony_ci u32 bus; 19268c2ecf20Sopenharmony_ci u32 target; 19278c2ecf20Sopenharmony_ci struct aac_ciss_identify_pd *identify_resp = NULL; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci lun_count = aac_get_safw_phys_lun_count(dev); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci for (i = 0; i < lun_count; ++i) { 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci bus = aac_get_safw_phys_bus(dev, i); 19348c2ecf20Sopenharmony_ci target = aac_get_safw_phys_target(dev, i); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci rcode = aac_issue_safw_bmic_identify(dev, 19378c2ecf20Sopenharmony_ci &identify_resp, bus, target); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 19408c2ecf20Sopenharmony_ci goto free_identify_resp; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci dev->hba_map[bus][target].safw_identify_resp = identify_resp; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ciout: 19468c2ecf20Sopenharmony_ci return rcode; 19478c2ecf20Sopenharmony_cifree_identify_resp: 19488c2ecf20Sopenharmony_ci aac_free_safw_all_identify_resp(dev, i); 19498c2ecf20Sopenharmony_ci goto out; 19508c2ecf20Sopenharmony_ci} 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci/** 19538c2ecf20Sopenharmony_ci * aac_set_safw_attr_all_targets- update current hba map with data from FW 19548c2ecf20Sopenharmony_ci * @dev: aac_dev structure 19558c2ecf20Sopenharmony_ci * 19568c2ecf20Sopenharmony_ci * Update our hba map with the information gathered from the FW 19578c2ecf20Sopenharmony_ci */ 19588c2ecf20Sopenharmony_cistatic void aac_set_safw_attr_all_targets(struct aac_dev *dev) 19598c2ecf20Sopenharmony_ci{ 19608c2ecf20Sopenharmony_ci /* ok and extended reporting */ 19618c2ecf20Sopenharmony_ci u32 lun_count, nexus; 19628c2ecf20Sopenharmony_ci u32 i, bus, target; 19638c2ecf20Sopenharmony_ci u8 expose_flag, attribs; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci lun_count = aac_get_safw_phys_lun_count(dev); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci dev->scan_counter++; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci for (i = 0; i < lun_count; ++i) { 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci bus = aac_get_safw_phys_bus(dev, i); 19728c2ecf20Sopenharmony_ci target = aac_get_safw_phys_target(dev, i); 19738c2ecf20Sopenharmony_ci expose_flag = aac_get_safw_phys_expose_flag(dev, i); 19748c2ecf20Sopenharmony_ci attribs = aac_get_safw_phys_attribs(dev, i); 19758c2ecf20Sopenharmony_ci nexus = aac_get_safw_phys_nexus(dev, i); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS) 19788c2ecf20Sopenharmony_ci continue; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci if (expose_flag != 0) { 19818c2ecf20Sopenharmony_ci dev->hba_map[bus][target].devtype = 19828c2ecf20Sopenharmony_ci AAC_DEVTYPE_RAID_MEMBER; 19838c2ecf20Sopenharmony_ci continue; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (nexus != 0 && (attribs & 8)) { 19878c2ecf20Sopenharmony_ci dev->hba_map[bus][target].devtype = 19888c2ecf20Sopenharmony_ci AAC_DEVTYPE_NATIVE_RAW; 19898c2ecf20Sopenharmony_ci dev->hba_map[bus][target].rmw_nexus = 19908c2ecf20Sopenharmony_ci nexus; 19918c2ecf20Sopenharmony_ci } else 19928c2ecf20Sopenharmony_ci dev->hba_map[bus][target].devtype = 19938c2ecf20Sopenharmony_ci AAC_DEVTYPE_ARC_RAW; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci dev->hba_map[bus][target].scan_counter = dev->scan_counter; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci aac_set_safw_target_qd(dev, bus, target); 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_cistatic int aac_setup_safw_targets(struct aac_dev *dev) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci int rcode = 0; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci rcode = aac_get_containers(dev); 20068c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 20078c2ecf20Sopenharmony_ci goto out; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci rcode = aac_get_safw_ciss_luns(dev); 20108c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 20118c2ecf20Sopenharmony_ci goto out; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci rcode = aac_get_safw_attr_all_targets(dev); 20148c2ecf20Sopenharmony_ci if (unlikely(rcode < 0)) 20158c2ecf20Sopenharmony_ci goto free_ciss_luns; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci aac_set_safw_attr_all_targets(dev); 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci aac_free_safw_all_identify_resp(dev, -1); 20208c2ecf20Sopenharmony_cifree_ciss_luns: 20218c2ecf20Sopenharmony_ci aac_free_safw_ciss_luns(dev); 20228c2ecf20Sopenharmony_ciout: 20238c2ecf20Sopenharmony_ci return rcode; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ciint aac_setup_safw_adapter(struct aac_dev *dev) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci return aac_setup_safw_targets(dev); 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ciint aac_get_adapter_info(struct aac_dev* dev) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci struct fib* fibptr; 20348c2ecf20Sopenharmony_ci int rcode; 20358c2ecf20Sopenharmony_ci u32 tmp, bus, target; 20368c2ecf20Sopenharmony_ci struct aac_adapter_info *info; 20378c2ecf20Sopenharmony_ci struct aac_bus_info *command; 20388c2ecf20Sopenharmony_ci struct aac_bus_info_response *bus_info; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (!(fibptr = aac_fib_alloc(dev))) 20418c2ecf20Sopenharmony_ci return -ENOMEM; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 20448c2ecf20Sopenharmony_ci info = (struct aac_adapter_info *) fib_data(fibptr); 20458c2ecf20Sopenharmony_ci memset(info,0,sizeof(*info)); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci rcode = aac_fib_send(RequestAdapterInfo, 20488c2ecf20Sopenharmony_ci fibptr, 20498c2ecf20Sopenharmony_ci sizeof(*info), 20508c2ecf20Sopenharmony_ci FsaNormal, 20518c2ecf20Sopenharmony_ci -1, 1, /* First `interrupt' command uses special wait */ 20528c2ecf20Sopenharmony_ci NULL, 20538c2ecf20Sopenharmony_ci NULL); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (rcode < 0) { 20568c2ecf20Sopenharmony_ci /* FIB should be freed only after 20578c2ecf20Sopenharmony_ci * getting the response from the F/W */ 20588c2ecf20Sopenharmony_ci if (rcode != -ERESTARTSYS) { 20598c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 20608c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci return rcode; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci memcpy(&dev->adapter_info, info, sizeof(*info)); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci dev->supplement_adapter_info.virt_device_bus = 0xffff; 20678c2ecf20Sopenharmony_ci if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) { 20688c2ecf20Sopenharmony_ci struct aac_supplement_adapter_info * sinfo; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci memset(sinfo,0,sizeof(*sinfo)); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci rcode = aac_fib_send(RequestSupplementAdapterInfo, 20778c2ecf20Sopenharmony_ci fibptr, 20788c2ecf20Sopenharmony_ci sizeof(*sinfo), 20798c2ecf20Sopenharmony_ci FsaNormal, 20808c2ecf20Sopenharmony_ci 1, 1, 20818c2ecf20Sopenharmony_ci NULL, 20828c2ecf20Sopenharmony_ci NULL); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (rcode >= 0) 20858c2ecf20Sopenharmony_ci memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo)); 20868c2ecf20Sopenharmony_ci if (rcode == -ERESTARTSYS) { 20878c2ecf20Sopenharmony_ci fibptr = aac_fib_alloc(dev); 20888c2ecf20Sopenharmony_ci if (!fibptr) 20898c2ecf20Sopenharmony_ci return -ENOMEM; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* reset all previous mapped devices (i.e. for init. after IOP_RESET) */ 20958c2ecf20Sopenharmony_ci for (bus = 0; bus < AAC_MAX_BUSES; bus++) { 20968c2ecf20Sopenharmony_ci for (target = 0; target < AAC_MAX_TARGETS; target++) { 20978c2ecf20Sopenharmony_ci dev->hba_map[bus][target].devtype = 0; 20988c2ecf20Sopenharmony_ci dev->hba_map[bus][target].qd_limit = 0; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* 21038c2ecf20Sopenharmony_ci * GetBusInfo 21048c2ecf20Sopenharmony_ci */ 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci aac_fib_init(fibptr); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci bus_info = (struct aac_bus_info_response *) fib_data(fibptr); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci memset(bus_info, 0, sizeof(*bus_info)); 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci command = (struct aac_bus_info *)bus_info; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci command->Command = cpu_to_le32(VM_Ioctl); 21158c2ecf20Sopenharmony_ci command->ObjType = cpu_to_le32(FT_DRIVE); 21168c2ecf20Sopenharmony_ci command->MethodId = cpu_to_le32(1); 21178c2ecf20Sopenharmony_ci command->CtlCmd = cpu_to_le32(GetBusInfo); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci rcode = aac_fib_send(ContainerCommand, 21208c2ecf20Sopenharmony_ci fibptr, 21218c2ecf20Sopenharmony_ci sizeof (*bus_info), 21228c2ecf20Sopenharmony_ci FsaNormal, 21238c2ecf20Sopenharmony_ci 1, 1, 21248c2ecf20Sopenharmony_ci NULL, NULL); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci /* reasoned default */ 21278c2ecf20Sopenharmony_ci dev->maximum_num_physicals = 16; 21288c2ecf20Sopenharmony_ci if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) { 21298c2ecf20Sopenharmony_ci dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus); 21308c2ecf20Sopenharmony_ci dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (!dev->in_reset) { 21348c2ecf20Sopenharmony_ci char buffer[16]; 21358c2ecf20Sopenharmony_ci tmp = le32_to_cpu(dev->adapter_info.kernelrev); 21368c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n", 21378c2ecf20Sopenharmony_ci dev->name, 21388c2ecf20Sopenharmony_ci dev->id, 21398c2ecf20Sopenharmony_ci tmp>>24, 21408c2ecf20Sopenharmony_ci (tmp>>16)&0xff, 21418c2ecf20Sopenharmony_ci tmp&0xff, 21428c2ecf20Sopenharmony_ci le32_to_cpu(dev->adapter_info.kernelbuild), 21438c2ecf20Sopenharmony_ci (int)sizeof(dev->supplement_adapter_info.build_date), 21448c2ecf20Sopenharmony_ci dev->supplement_adapter_info.build_date); 21458c2ecf20Sopenharmony_ci tmp = le32_to_cpu(dev->adapter_info.monitorrev); 21468c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n", 21478c2ecf20Sopenharmony_ci dev->name, dev->id, 21488c2ecf20Sopenharmony_ci tmp>>24,(tmp>>16)&0xff,tmp&0xff, 21498c2ecf20Sopenharmony_ci le32_to_cpu(dev->adapter_info.monitorbuild)); 21508c2ecf20Sopenharmony_ci tmp = le32_to_cpu(dev->adapter_info.biosrev); 21518c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n", 21528c2ecf20Sopenharmony_ci dev->name, dev->id, 21538c2ecf20Sopenharmony_ci tmp>>24,(tmp>>16)&0xff,tmp&0xff, 21548c2ecf20Sopenharmony_ci le32_to_cpu(dev->adapter_info.biosbuild)); 21558c2ecf20Sopenharmony_ci buffer[0] = '\0'; 21568c2ecf20Sopenharmony_ci if (aac_get_serial_number( 21578c2ecf20Sopenharmony_ci shost_to_class(dev->scsi_host_ptr), buffer)) 21588c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: serial %s", 21598c2ecf20Sopenharmony_ci dev->name, dev->id, buffer); 21608c2ecf20Sopenharmony_ci if (dev->supplement_adapter_info.vpd_info.tsid[0]) { 21618c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: TSID %.*s\n", 21628c2ecf20Sopenharmony_ci dev->name, dev->id, 21638c2ecf20Sopenharmony_ci (int)sizeof(dev->supplement_adapter_info 21648c2ecf20Sopenharmony_ci .vpd_info.tsid), 21658c2ecf20Sopenharmony_ci dev->supplement_adapter_info.vpd_info.tsid); 21668c2ecf20Sopenharmony_ci } 21678c2ecf20Sopenharmony_ci if (!aac_check_reset || ((aac_check_reset == 1) && 21688c2ecf20Sopenharmony_ci (dev->supplement_adapter_info.supported_options2 & 21698c2ecf20Sopenharmony_ci AAC_OPTION_IGNORE_RESET))) { 21708c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", 21718c2ecf20Sopenharmony_ci dev->name, dev->id); 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci dev->cache_protected = 0; 21768c2ecf20Sopenharmony_ci dev->jbod = ((dev->supplement_adapter_info.feature_bits & 21778c2ecf20Sopenharmony_ci AAC_FEATURE_JBOD) != 0); 21788c2ecf20Sopenharmony_ci dev->nondasd_support = 0; 21798c2ecf20Sopenharmony_ci dev->raid_scsi_mode = 0; 21808c2ecf20Sopenharmony_ci if(dev->adapter_info.options & AAC_OPT_NONDASD) 21818c2ecf20Sopenharmony_ci dev->nondasd_support = 1; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci /* 21848c2ecf20Sopenharmony_ci * If the firmware supports ROMB RAID/SCSI mode and we are currently 21858c2ecf20Sopenharmony_ci * in RAID/SCSI mode, set the flag. For now if in this mode we will 21868c2ecf20Sopenharmony_ci * force nondasd support on. If we decide to allow the non-dasd flag 21878c2ecf20Sopenharmony_ci * additional changes changes will have to be made to support 21888c2ecf20Sopenharmony_ci * RAID/SCSI. the function aac_scsi_cmd in this module will have to be 21898c2ecf20Sopenharmony_ci * changed to support the new dev->raid_scsi_mode flag instead of 21908c2ecf20Sopenharmony_ci * leaching off of the dev->nondasd_support flag. Also in linit.c the 21918c2ecf20Sopenharmony_ci * function aac_detect will have to be modified where it sets up the 21928c2ecf20Sopenharmony_ci * max number of channels based on the aac->nondasd_support flag only. 21938c2ecf20Sopenharmony_ci */ 21948c2ecf20Sopenharmony_ci if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) && 21958c2ecf20Sopenharmony_ci (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) { 21968c2ecf20Sopenharmony_ci dev->nondasd_support = 1; 21978c2ecf20Sopenharmony_ci dev->raid_scsi_mode = 1; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci if (dev->raid_scsi_mode != 0) 22008c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n", 22018c2ecf20Sopenharmony_ci dev->name, dev->id); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (nondasd != -1) 22048c2ecf20Sopenharmony_ci dev->nondasd_support = (nondasd!=0); 22058c2ecf20Sopenharmony_ci if (dev->nondasd_support && !dev->in_reset) 22068c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32)) 22098c2ecf20Sopenharmony_ci dev->needs_dac = 1; 22108c2ecf20Sopenharmony_ci dev->dac_support = 0; 22118c2ecf20Sopenharmony_ci if ((sizeof(dma_addr_t) > 4) && dev->needs_dac && 22128c2ecf20Sopenharmony_ci (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) { 22138c2ecf20Sopenharmony_ci if (!dev->in_reset) 22148c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%d: 64bit support enabled.\n", 22158c2ecf20Sopenharmony_ci dev->name, dev->id); 22168c2ecf20Sopenharmony_ci dev->dac_support = 1; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci if(dacmode != -1) { 22208c2ecf20Sopenharmony_ci dev->dac_support = (dacmode!=0); 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci /* avoid problems with AAC_QUIRK_SCSI_32 controllers */ 22248c2ecf20Sopenharmony_ci if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks 22258c2ecf20Sopenharmony_ci & AAC_QUIRK_SCSI_32)) { 22268c2ecf20Sopenharmony_ci dev->nondasd_support = 0; 22278c2ecf20Sopenharmony_ci dev->jbod = 0; 22288c2ecf20Sopenharmony_ci expose_physicals = 0; 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci if (dev->dac_support) { 22328c2ecf20Sopenharmony_ci if (!dma_set_mask(&dev->pdev->dev, DMA_BIT_MASK(64))) { 22338c2ecf20Sopenharmony_ci if (!dev->in_reset) 22348c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "64 Bit DAC enabled\n"); 22358c2ecf20Sopenharmony_ci } else if (!dma_set_mask(&dev->pdev->dev, DMA_BIT_MASK(32))) { 22368c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "DMA mask set failed, 64 Bit DAC disabled\n"); 22378c2ecf20Sopenharmony_ci dev->dac_support = 0; 22388c2ecf20Sopenharmony_ci } else { 22398c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "No suitable DMA available\n"); 22408c2ecf20Sopenharmony_ci rcode = -ENOMEM; 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci /* 22448c2ecf20Sopenharmony_ci * Deal with configuring for the individualized limits of each packet 22458c2ecf20Sopenharmony_ci * interface. 22468c2ecf20Sopenharmony_ci */ 22478c2ecf20Sopenharmony_ci dev->a_ops.adapter_scsi = (dev->dac_support) 22488c2ecf20Sopenharmony_ci ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32) 22498c2ecf20Sopenharmony_ci ? aac_scsi_32_64 22508c2ecf20Sopenharmony_ci : aac_scsi_64) 22518c2ecf20Sopenharmony_ci : aac_scsi_32; 22528c2ecf20Sopenharmony_ci if (dev->raw_io_interface) { 22538c2ecf20Sopenharmony_ci dev->a_ops.adapter_bounds = (dev->raw_io_64) 22548c2ecf20Sopenharmony_ci ? aac_bounds_64 22558c2ecf20Sopenharmony_ci : aac_bounds_32; 22568c2ecf20Sopenharmony_ci dev->a_ops.adapter_read = aac_read_raw_io; 22578c2ecf20Sopenharmony_ci dev->a_ops.adapter_write = aac_write_raw_io; 22588c2ecf20Sopenharmony_ci } else { 22598c2ecf20Sopenharmony_ci dev->a_ops.adapter_bounds = aac_bounds_32; 22608c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - 22618c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr) - 22628c2ecf20Sopenharmony_ci sizeof(struct aac_write) + sizeof(struct sgentry)) / 22638c2ecf20Sopenharmony_ci sizeof(struct sgentry); 22648c2ecf20Sopenharmony_ci if (dev->dac_support) { 22658c2ecf20Sopenharmony_ci dev->a_ops.adapter_read = aac_read_block64; 22668c2ecf20Sopenharmony_ci dev->a_ops.adapter_write = aac_write_block64; 22678c2ecf20Sopenharmony_ci /* 22688c2ecf20Sopenharmony_ci * 38 scatter gather elements 22698c2ecf20Sopenharmony_ci */ 22708c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize = 22718c2ecf20Sopenharmony_ci (dev->max_fib_size - 22728c2ecf20Sopenharmony_ci sizeof(struct aac_fibhdr) - 22738c2ecf20Sopenharmony_ci sizeof(struct aac_write64) + 22748c2ecf20Sopenharmony_ci sizeof(struct sgentry64)) / 22758c2ecf20Sopenharmony_ci sizeof(struct sgentry64); 22768c2ecf20Sopenharmony_ci } else { 22778c2ecf20Sopenharmony_ci dev->a_ops.adapter_read = aac_read_block; 22788c2ecf20Sopenharmony_ci dev->a_ops.adapter_write = aac_write_block; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; 22818c2ecf20Sopenharmony_ci if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { 22828c2ecf20Sopenharmony_ci /* 22838c2ecf20Sopenharmony_ci * Worst case size that could cause sg overflow when 22848c2ecf20Sopenharmony_ci * we break up SG elements that are larger than 64KB. 22858c2ecf20Sopenharmony_ci * Would be nice if we could tell the SCSI layer what 22868c2ecf20Sopenharmony_ci * the maximum SG element size can be. Worst case is 22878c2ecf20Sopenharmony_ci * (sg_tablesize-1) 4KB elements with one 64KB 22888c2ecf20Sopenharmony_ci * element. 22898c2ecf20Sopenharmony_ci * 32bit -> 468 or 238KB 64bit -> 424 or 212KB 22908c2ecf20Sopenharmony_ci */ 22918c2ecf20Sopenharmony_ci dev->scsi_host_ptr->max_sectors = 22928c2ecf20Sopenharmony_ci (dev->scsi_host_ptr->sg_tablesize * 8) + 112; 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci if (!dev->sync_mode && dev->sa_firmware && 22968c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize > HBA_MAX_SG_SEPARATE) 22978c2ecf20Sopenharmony_ci dev->scsi_host_ptr->sg_tablesize = dev->sg_tablesize = 22988c2ecf20Sopenharmony_ci HBA_MAX_SG_SEPARATE; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci /* FIB should be freed only after getting the response from the F/W */ 23018c2ecf20Sopenharmony_ci if (rcode != -ERESTARTSYS) { 23028c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 23038c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci return rcode; 23078c2ecf20Sopenharmony_ci} 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic void io_callback(void *context, struct fib * fibptr) 23118c2ecf20Sopenharmony_ci{ 23128c2ecf20Sopenharmony_ci struct aac_dev *dev; 23138c2ecf20Sopenharmony_ci struct aac_read_reply *readreply; 23148c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd; 23158c2ecf20Sopenharmony_ci u32 cid; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 23208c2ecf20Sopenharmony_ci return; 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci dev = fibptr->dev; 23238c2ecf20Sopenharmony_ci cid = scmd_id(scsicmd); 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci if (nblank(dprintk(x))) { 23268c2ecf20Sopenharmony_ci u64 lba; 23278c2ecf20Sopenharmony_ci switch (scsicmd->cmnd[0]) { 23288c2ecf20Sopenharmony_ci case WRITE_6: 23298c2ecf20Sopenharmony_ci case READ_6: 23308c2ecf20Sopenharmony_ci lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 23318c2ecf20Sopenharmony_ci (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 23328c2ecf20Sopenharmony_ci break; 23338c2ecf20Sopenharmony_ci case WRITE_16: 23348c2ecf20Sopenharmony_ci case READ_16: 23358c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 56) | 23368c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[3] << 48) | 23378c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[4] << 40) | 23388c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[5] << 32) | 23398c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[6] << 24) | 23408c2ecf20Sopenharmony_ci (scsicmd->cmnd[7] << 16) | 23418c2ecf20Sopenharmony_ci (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 23428c2ecf20Sopenharmony_ci break; 23438c2ecf20Sopenharmony_ci case WRITE_12: 23448c2ecf20Sopenharmony_ci case READ_12: 23458c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | 23468c2ecf20Sopenharmony_ci (scsicmd->cmnd[3] << 16) | 23478c2ecf20Sopenharmony_ci (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 23488c2ecf20Sopenharmony_ci break; 23498c2ecf20Sopenharmony_ci default: 23508c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | 23518c2ecf20Sopenharmony_ci (scsicmd->cmnd[3] << 16) | 23528c2ecf20Sopenharmony_ci (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 23538c2ecf20Sopenharmony_ci break; 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci printk(KERN_DEBUG 23568c2ecf20Sopenharmony_ci "io_callback[cpu %d]: lba = %llu, t = %ld.\n", 23578c2ecf20Sopenharmony_ci smp_processor_id(), (unsigned long long)lba, jiffies); 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci scsi_dma_unmap(scsicmd); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci readreply = (struct aac_read_reply *)fib_data(fibptr); 23658c2ecf20Sopenharmony_ci switch (le32_to_cpu(readreply->status)) { 23668c2ecf20Sopenharmony_ci case ST_OK: 23678c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 23688c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 23698c2ecf20Sopenharmony_ci dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE; 23708c2ecf20Sopenharmony_ci break; 23718c2ecf20Sopenharmony_ci case ST_NOT_READY: 23728c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 23738c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 23748c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY, 23758c2ecf20Sopenharmony_ci SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0); 23768c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 23778c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 23788c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 23798c2ecf20Sopenharmony_ci break; 23808c2ecf20Sopenharmony_ci case ST_MEDERR: 23818c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 23828c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 23838c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, MEDIUM_ERROR, 23848c2ecf20Sopenharmony_ci SENCODE_UNRECOVERED_READ_ERROR, ASENCODE_NO_SENSE, 0, 0); 23858c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 23868c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 23878c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 23888c2ecf20Sopenharmony_ci break; 23898c2ecf20Sopenharmony_ci default: 23908c2ecf20Sopenharmony_ci#ifdef AAC_DETAILED_STATUS_INFO 23918c2ecf20Sopenharmony_ci printk(KERN_WARNING "io_callback: io failed, status = %d\n", 23928c2ecf20Sopenharmony_ci le32_to_cpu(readreply->status)); 23938c2ecf20Sopenharmony_ci#endif 23948c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 23958c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 23968c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 23978c2ecf20Sopenharmony_ci HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 23988c2ecf20Sopenharmony_ci ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 23998c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 24008c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 24018c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 24028c2ecf20Sopenharmony_ci break; 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 24078c2ecf20Sopenharmony_ci} 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_cistatic int aac_read(struct scsi_cmnd * scsicmd) 24108c2ecf20Sopenharmony_ci{ 24118c2ecf20Sopenharmony_ci u64 lba; 24128c2ecf20Sopenharmony_ci u32 count; 24138c2ecf20Sopenharmony_ci int status; 24148c2ecf20Sopenharmony_ci struct aac_dev *dev; 24158c2ecf20Sopenharmony_ci struct fib * cmd_fibcontext; 24168c2ecf20Sopenharmony_ci int cid; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 24198c2ecf20Sopenharmony_ci /* 24208c2ecf20Sopenharmony_ci * Get block address and transfer length 24218c2ecf20Sopenharmony_ci */ 24228c2ecf20Sopenharmony_ci switch (scsicmd->cmnd[0]) { 24238c2ecf20Sopenharmony_ci case READ_6: 24248c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd))); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 24278c2ecf20Sopenharmony_ci (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 24288c2ecf20Sopenharmony_ci count = scsicmd->cmnd[4]; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (count == 0) 24318c2ecf20Sopenharmony_ci count = 256; 24328c2ecf20Sopenharmony_ci break; 24338c2ecf20Sopenharmony_ci case READ_16: 24348c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd))); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 56) | 24378c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[3] << 48) | 24388c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[4] << 40) | 24398c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[5] << 32) | 24408c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[6] << 24) | 24418c2ecf20Sopenharmony_ci (scsicmd->cmnd[7] << 16) | 24428c2ecf20Sopenharmony_ci (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 24438c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[10] << 24) | 24448c2ecf20Sopenharmony_ci (scsicmd->cmnd[11] << 16) | 24458c2ecf20Sopenharmony_ci (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; 24468c2ecf20Sopenharmony_ci break; 24478c2ecf20Sopenharmony_ci case READ_12: 24488c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd))); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | 24518c2ecf20Sopenharmony_ci (scsicmd->cmnd[3] << 16) | 24528c2ecf20Sopenharmony_ci (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 24538c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[6] << 24) | 24548c2ecf20Sopenharmony_ci (scsicmd->cmnd[7] << 16) | 24558c2ecf20Sopenharmony_ci (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 24568c2ecf20Sopenharmony_ci break; 24578c2ecf20Sopenharmony_ci default: 24588c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd))); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | 24618c2ecf20Sopenharmony_ci (scsicmd->cmnd[3] << 16) | 24628c2ecf20Sopenharmony_ci (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 24638c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; 24648c2ecf20Sopenharmony_ci break; 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { 24688c2ecf20Sopenharmony_ci cid = scmd_id(scsicmd); 24698c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 24708c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 24718c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 24728c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 24738c2ecf20Sopenharmony_ci ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE, 24748c2ecf20Sopenharmony_ci ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 24758c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 24768c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 24778c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 24788c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", 24838c2ecf20Sopenharmony_ci smp_processor_id(), (unsigned long long)lba, jiffies)); 24848c2ecf20Sopenharmony_ci if (aac_adapter_bounds(dev,scsicmd,lba)) 24858c2ecf20Sopenharmony_ci return 0; 24868c2ecf20Sopenharmony_ci /* 24878c2ecf20Sopenharmony_ci * Alocate and initialize a Fib 24888c2ecf20Sopenharmony_ci */ 24898c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 24908c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 24918c2ecf20Sopenharmony_ci status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* 24948c2ecf20Sopenharmony_ci * Check that the command queued to the controller 24958c2ecf20Sopenharmony_ci */ 24968c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 24978c2ecf20Sopenharmony_ci return 0; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); 25008c2ecf20Sopenharmony_ci /* 25018c2ecf20Sopenharmony_ci * For some reason, the Fib didn't queue, return QUEUE_FULL 25028c2ecf20Sopenharmony_ci */ 25038c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; 25048c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 25058c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 25068c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 25078c2ecf20Sopenharmony_ci return 0; 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_cistatic int aac_write(struct scsi_cmnd * scsicmd) 25118c2ecf20Sopenharmony_ci{ 25128c2ecf20Sopenharmony_ci u64 lba; 25138c2ecf20Sopenharmony_ci u32 count; 25148c2ecf20Sopenharmony_ci int fua; 25158c2ecf20Sopenharmony_ci int status; 25168c2ecf20Sopenharmony_ci struct aac_dev *dev; 25178c2ecf20Sopenharmony_ci struct fib * cmd_fibcontext; 25188c2ecf20Sopenharmony_ci int cid; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 25218c2ecf20Sopenharmony_ci /* 25228c2ecf20Sopenharmony_ci * Get block address and transfer length 25238c2ecf20Sopenharmony_ci */ 25248c2ecf20Sopenharmony_ci if (scsicmd->cmnd[0] == WRITE_6) /* 6 byte command */ 25258c2ecf20Sopenharmony_ci { 25268c2ecf20Sopenharmony_ci lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; 25278c2ecf20Sopenharmony_ci count = scsicmd->cmnd[4]; 25288c2ecf20Sopenharmony_ci if (count == 0) 25298c2ecf20Sopenharmony_ci count = 256; 25308c2ecf20Sopenharmony_ci fua = 0; 25318c2ecf20Sopenharmony_ci } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */ 25328c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd))); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 56) | 25358c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[3] << 48) | 25368c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[4] << 40) | 25378c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[5] << 32) | 25388c2ecf20Sopenharmony_ci ((u64)scsicmd->cmnd[6] << 24) | 25398c2ecf20Sopenharmony_ci (scsicmd->cmnd[7] << 16) | 25408c2ecf20Sopenharmony_ci (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 25418c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | 25428c2ecf20Sopenharmony_ci (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; 25438c2ecf20Sopenharmony_ci fua = scsicmd->cmnd[1] & 0x8; 25448c2ecf20Sopenharmony_ci } else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */ 25458c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd))); 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) 25488c2ecf20Sopenharmony_ci | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 25498c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) 25508c2ecf20Sopenharmony_ci | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; 25518c2ecf20Sopenharmony_ci fua = scsicmd->cmnd[1] & 0x8; 25528c2ecf20Sopenharmony_ci } else { 25538c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd))); 25548c2ecf20Sopenharmony_ci lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; 25558c2ecf20Sopenharmony_ci count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; 25568c2ecf20Sopenharmony_ci fua = scsicmd->cmnd[1] & 0x8; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { 25608c2ecf20Sopenharmony_ci cid = scmd_id(scsicmd); 25618c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); 25628c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 25638c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 25648c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 25658c2ecf20Sopenharmony_ci ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE, 25668c2ecf20Sopenharmony_ci ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 25678c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 25688c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 25698c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 25708c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 25718c2ecf20Sopenharmony_ci return 0; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", 25758c2ecf20Sopenharmony_ci smp_processor_id(), (unsigned long long)lba, jiffies)); 25768c2ecf20Sopenharmony_ci if (aac_adapter_bounds(dev,scsicmd,lba)) 25778c2ecf20Sopenharmony_ci return 0; 25788c2ecf20Sopenharmony_ci /* 25798c2ecf20Sopenharmony_ci * Allocate and initialize a Fib then setup a BlockWrite command 25808c2ecf20Sopenharmony_ci */ 25818c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 25828c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 25838c2ecf20Sopenharmony_ci status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci /* 25868c2ecf20Sopenharmony_ci * Check that the command queued to the controller 25878c2ecf20Sopenharmony_ci */ 25888c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 25898c2ecf20Sopenharmony_ci return 0; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status); 25928c2ecf20Sopenharmony_ci /* 25938c2ecf20Sopenharmony_ci * For some reason, the Fib didn't queue, return QUEUE_FULL 25948c2ecf20Sopenharmony_ci */ 25958c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; 25968c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 25998c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 26008c2ecf20Sopenharmony_ci return 0; 26018c2ecf20Sopenharmony_ci} 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_cistatic void synchronize_callback(void *context, struct fib *fibptr) 26048c2ecf20Sopenharmony_ci{ 26058c2ecf20Sopenharmony_ci struct aac_synchronize_reply *synchronizereply; 26068c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = context; 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci if (!aac_valid_context(cmd, fibptr)) 26098c2ecf20Sopenharmony_ci return; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 26128c2ecf20Sopenharmony_ci smp_processor_id(), jiffies)); 26138c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci synchronizereply = fib_data(fibptr); 26178c2ecf20Sopenharmony_ci if (le32_to_cpu(synchronizereply->status) == CT_OK) 26188c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | 26198c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 26208c2ecf20Sopenharmony_ci else { 26218c2ecf20Sopenharmony_ci struct scsi_device *sdev = cmd->device; 26228c2ecf20Sopenharmony_ci struct aac_dev *dev = fibptr->dev; 26238c2ecf20Sopenharmony_ci u32 cid = sdev_id(sdev); 26248c2ecf20Sopenharmony_ci printk(KERN_WARNING 26258c2ecf20Sopenharmony_ci "synchronize_callback: synchronize failed, status = %d\n", 26268c2ecf20Sopenharmony_ci le32_to_cpu(synchronizereply->status)); 26278c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16 | 26288c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; 26298c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 26308c2ecf20Sopenharmony_ci HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, 26318c2ecf20Sopenharmony_ci ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); 26328c2ecf20Sopenharmony_ci memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 26338c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 26348c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 26388c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 26398c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic int aac_synchronize(struct scsi_cmnd *scsicmd) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci int status; 26458c2ecf20Sopenharmony_ci struct fib *cmd_fibcontext; 26468c2ecf20Sopenharmony_ci struct aac_synchronize *synchronizecmd; 26478c2ecf20Sopenharmony_ci struct scsi_device *sdev = scsicmd->device; 26488c2ecf20Sopenharmony_ci struct aac_dev *aac; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci aac = (struct aac_dev *)sdev->host->hostdata; 26518c2ecf20Sopenharmony_ci if (aac->in_reset) 26528c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci /* 26558c2ecf20Sopenharmony_ci * Allocate and initialize a Fib 26568c2ecf20Sopenharmony_ci */ 26578c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd); 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci aac_fib_init(cmd_fibcontext); 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci synchronizecmd = fib_data(cmd_fibcontext); 26628c2ecf20Sopenharmony_ci synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); 26638c2ecf20Sopenharmony_ci synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); 26648c2ecf20Sopenharmony_ci synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); 26658c2ecf20Sopenharmony_ci synchronizecmd->count = 26668c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); 26678c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci /* 26708c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 26718c2ecf20Sopenharmony_ci */ 26728c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 26738c2ecf20Sopenharmony_ci cmd_fibcontext, 26748c2ecf20Sopenharmony_ci sizeof(struct aac_synchronize), 26758c2ecf20Sopenharmony_ci FsaNormal, 26768c2ecf20Sopenharmony_ci 0, 1, 26778c2ecf20Sopenharmony_ci (fib_callback)synchronize_callback, 26788c2ecf20Sopenharmony_ci (void *)scsicmd); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci /* 26818c2ecf20Sopenharmony_ci * Check that the command queued to the controller 26828c2ecf20Sopenharmony_ci */ 26838c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 26848c2ecf20Sopenharmony_ci return 0; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci printk(KERN_WARNING 26878c2ecf20Sopenharmony_ci "aac_synchronize: aac_fib_send failed with status: %d.\n", status); 26888c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 26898c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 26908c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 26918c2ecf20Sopenharmony_ci} 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_cistatic void aac_start_stop_callback(void *context, struct fib *fibptr) 26948c2ecf20Sopenharmony_ci{ 26958c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd = context; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 26988c2ecf20Sopenharmony_ci return; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 27058c2ecf20Sopenharmony_ci aac_fib_free(fibptr); 27068c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 27078c2ecf20Sopenharmony_ci} 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_cistatic int aac_start_stop(struct scsi_cmnd *scsicmd) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci int status; 27128c2ecf20Sopenharmony_ci struct fib *cmd_fibcontext; 27138c2ecf20Sopenharmony_ci struct aac_power_management *pmcmd; 27148c2ecf20Sopenharmony_ci struct scsi_device *sdev = scsicmd->device; 27158c2ecf20Sopenharmony_ci struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci if (!(aac->supplement_adapter_info.supported_options2 & 27188c2ecf20Sopenharmony_ci AAC_OPTION_POWER_MANAGEMENT)) { 27198c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 27208c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 27218c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 27228c2ecf20Sopenharmony_ci return 0; 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci if (aac->in_reset) 27268c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci /* 27298c2ecf20Sopenharmony_ci * Allocate and initialize a Fib 27308c2ecf20Sopenharmony_ci */ 27318c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(aac, scsicmd); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci aac_fib_init(cmd_fibcontext); 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci pmcmd = fib_data(cmd_fibcontext); 27368c2ecf20Sopenharmony_ci pmcmd->command = cpu_to_le32(VM_ContainerConfig); 27378c2ecf20Sopenharmony_ci pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT); 27388c2ecf20Sopenharmony_ci /* Eject bit ignored, not relevant */ 27398c2ecf20Sopenharmony_ci pmcmd->sub = (scsicmd->cmnd[4] & 1) ? 27408c2ecf20Sopenharmony_ci cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT); 27418c2ecf20Sopenharmony_ci pmcmd->cid = cpu_to_le32(sdev_id(sdev)); 27428c2ecf20Sopenharmony_ci pmcmd->parm = (scsicmd->cmnd[1] & 1) ? 27438c2ecf20Sopenharmony_ci cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0; 27448c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci /* 27478c2ecf20Sopenharmony_ci * Now send the Fib to the adapter 27488c2ecf20Sopenharmony_ci */ 27498c2ecf20Sopenharmony_ci status = aac_fib_send(ContainerCommand, 27508c2ecf20Sopenharmony_ci cmd_fibcontext, 27518c2ecf20Sopenharmony_ci sizeof(struct aac_power_management), 27528c2ecf20Sopenharmony_ci FsaNormal, 27538c2ecf20Sopenharmony_ci 0, 1, 27548c2ecf20Sopenharmony_ci (fib_callback)aac_start_stop_callback, 27558c2ecf20Sopenharmony_ci (void *)scsicmd); 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci /* 27588c2ecf20Sopenharmony_ci * Check that the command queued to the controller 27598c2ecf20Sopenharmony_ci */ 27608c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 27618c2ecf20Sopenharmony_ci return 0; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 27648c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 27658c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 27668c2ecf20Sopenharmony_ci} 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci/** 27698c2ecf20Sopenharmony_ci * aac_scsi_cmd() - Process SCSI command 27708c2ecf20Sopenharmony_ci * @scsicmd: SCSI command block 27718c2ecf20Sopenharmony_ci * 27728c2ecf20Sopenharmony_ci * Emulate a SCSI command and queue the required request for the 27738c2ecf20Sopenharmony_ci * aacraid firmware. 27748c2ecf20Sopenharmony_ci */ 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ciint aac_scsi_cmd(struct scsi_cmnd * scsicmd) 27778c2ecf20Sopenharmony_ci{ 27788c2ecf20Sopenharmony_ci u32 cid, bus; 27798c2ecf20Sopenharmony_ci struct Scsi_Host *host = scsicmd->device->host; 27808c2ecf20Sopenharmony_ci struct aac_dev *dev = (struct aac_dev *)host->hostdata; 27818c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci if (fsa_dev_ptr == NULL) 27848c2ecf20Sopenharmony_ci return -1; 27858c2ecf20Sopenharmony_ci /* 27868c2ecf20Sopenharmony_ci * If the bus, id or lun is out of range, return fail 27878c2ecf20Sopenharmony_ci * Test does not apply to ID 16, the pseudo id for the controller 27888c2ecf20Sopenharmony_ci * itself. 27898c2ecf20Sopenharmony_ci */ 27908c2ecf20Sopenharmony_ci cid = scmd_id(scsicmd); 27918c2ecf20Sopenharmony_ci if (cid != host->this_id) { 27928c2ecf20Sopenharmony_ci if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) { 27938c2ecf20Sopenharmony_ci if((cid >= dev->maximum_num_containers) || 27948c2ecf20Sopenharmony_ci (scsicmd->device->lun != 0)) { 27958c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16; 27968c2ecf20Sopenharmony_ci goto scsi_done_ret; 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci /* 28008c2ecf20Sopenharmony_ci * If the target container doesn't exist, it may have 28018c2ecf20Sopenharmony_ci * been newly created 28028c2ecf20Sopenharmony_ci */ 28038c2ecf20Sopenharmony_ci if (((fsa_dev_ptr[cid].valid & 1) == 0) || 28048c2ecf20Sopenharmony_ci (fsa_dev_ptr[cid].sense_data.sense_key == 28058c2ecf20Sopenharmony_ci NOT_READY)) { 28068c2ecf20Sopenharmony_ci switch (scsicmd->cmnd[0]) { 28078c2ecf20Sopenharmony_ci case SERVICE_ACTION_IN_16: 28088c2ecf20Sopenharmony_ci if (!(dev->raw_io_interface) || 28098c2ecf20Sopenharmony_ci !(dev->raw_io_64) || 28108c2ecf20Sopenharmony_ci ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) 28118c2ecf20Sopenharmony_ci break; 28128c2ecf20Sopenharmony_ci fallthrough; 28138c2ecf20Sopenharmony_ci case INQUIRY: 28148c2ecf20Sopenharmony_ci case READ_CAPACITY: 28158c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 28168c2ecf20Sopenharmony_ci if (dev->in_reset) 28178c2ecf20Sopenharmony_ci return -1; 28188c2ecf20Sopenharmony_ci return _aac_probe_container(scsicmd, 28198c2ecf20Sopenharmony_ci aac_probe_container_callback2); 28208c2ecf20Sopenharmony_ci default: 28218c2ecf20Sopenharmony_ci break; 28228c2ecf20Sopenharmony_ci } 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci } else { /* check for physical non-dasd devices */ 28258c2ecf20Sopenharmony_ci bus = aac_logical_to_phys(scmd_channel(scsicmd)); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && 28288c2ecf20Sopenharmony_ci dev->hba_map[bus][cid].devtype 28298c2ecf20Sopenharmony_ci == AAC_DEVTYPE_NATIVE_RAW) { 28308c2ecf20Sopenharmony_ci if (dev->in_reset) 28318c2ecf20Sopenharmony_ci return -1; 28328c2ecf20Sopenharmony_ci return aac_send_hba_fib(scsicmd); 28338c2ecf20Sopenharmony_ci } else if (dev->nondasd_support || expose_physicals || 28348c2ecf20Sopenharmony_ci dev->jbod) { 28358c2ecf20Sopenharmony_ci if (dev->in_reset) 28368c2ecf20Sopenharmony_ci return -1; 28378c2ecf20Sopenharmony_ci return aac_send_srb_fib(scsicmd); 28388c2ecf20Sopenharmony_ci } else { 28398c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16; 28408c2ecf20Sopenharmony_ci goto scsi_done_ret; 28418c2ecf20Sopenharmony_ci } 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci /* 28458c2ecf20Sopenharmony_ci * else Command for the controller itself 28468c2ecf20Sopenharmony_ci */ 28478c2ecf20Sopenharmony_ci else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */ 28488c2ecf20Sopenharmony_ci (scsicmd->cmnd[0] != TEST_UNIT_READY)) 28498c2ecf20Sopenharmony_ci { 28508c2ecf20Sopenharmony_ci dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); 28518c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; 28528c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 28538c2ecf20Sopenharmony_ci ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, 28548c2ecf20Sopenharmony_ci ASENCODE_INVALID_COMMAND, 0, 0); 28558c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 28568c2ecf20Sopenharmony_ci min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), 28578c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 28588c2ecf20Sopenharmony_ci goto scsi_done_ret; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci switch (scsicmd->cmnd[0]) { 28628c2ecf20Sopenharmony_ci case READ_6: 28638c2ecf20Sopenharmony_ci case READ_10: 28648c2ecf20Sopenharmony_ci case READ_12: 28658c2ecf20Sopenharmony_ci case READ_16: 28668c2ecf20Sopenharmony_ci if (dev->in_reset) 28678c2ecf20Sopenharmony_ci return -1; 28688c2ecf20Sopenharmony_ci return aac_read(scsicmd); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci case WRITE_6: 28718c2ecf20Sopenharmony_ci case WRITE_10: 28728c2ecf20Sopenharmony_ci case WRITE_12: 28738c2ecf20Sopenharmony_ci case WRITE_16: 28748c2ecf20Sopenharmony_ci if (dev->in_reset) 28758c2ecf20Sopenharmony_ci return -1; 28768c2ecf20Sopenharmony_ci return aac_write(scsicmd); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci case SYNCHRONIZE_CACHE: 28798c2ecf20Sopenharmony_ci if (((aac_cache & 6) == 6) && dev->cache_protected) { 28808c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 28818c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 28828c2ecf20Sopenharmony_ci break; 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci /* Issue FIB to tell Firmware to flush it's cache */ 28858c2ecf20Sopenharmony_ci if ((aac_cache & 6) != 2) 28868c2ecf20Sopenharmony_ci return aac_synchronize(scsicmd); 28878c2ecf20Sopenharmony_ci fallthrough; 28888c2ecf20Sopenharmony_ci case INQUIRY: 28898c2ecf20Sopenharmony_ci { 28908c2ecf20Sopenharmony_ci struct inquiry_data inq_data; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); 28938c2ecf20Sopenharmony_ci memset(&inq_data, 0, sizeof (struct inquiry_data)); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) { 28968c2ecf20Sopenharmony_ci char *arr = (char *)&inq_data; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci /* EVPD bit set */ 28998c2ecf20Sopenharmony_ci arr[0] = (scmd_id(scsicmd) == host->this_id) ? 29008c2ecf20Sopenharmony_ci INQD_PDT_PROC : INQD_PDT_DA; 29018c2ecf20Sopenharmony_ci if (scsicmd->cmnd[2] == 0) { 29028c2ecf20Sopenharmony_ci /* supported vital product data pages */ 29038c2ecf20Sopenharmony_ci arr[3] = 3; 29048c2ecf20Sopenharmony_ci arr[4] = 0x0; 29058c2ecf20Sopenharmony_ci arr[5] = 0x80; 29068c2ecf20Sopenharmony_ci arr[6] = 0x83; 29078c2ecf20Sopenharmony_ci arr[1] = scsicmd->cmnd[2]; 29088c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq_data, 29098c2ecf20Sopenharmony_ci sizeof(inq_data)); 29108c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | 29118c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | 29128c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 29138c2ecf20Sopenharmony_ci } else if (scsicmd->cmnd[2] == 0x80) { 29148c2ecf20Sopenharmony_ci /* unit serial number page */ 29158c2ecf20Sopenharmony_ci arr[3] = setinqserial(dev, &arr[4], 29168c2ecf20Sopenharmony_ci scmd_id(scsicmd)); 29178c2ecf20Sopenharmony_ci arr[1] = scsicmd->cmnd[2]; 29188c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq_data, 29198c2ecf20Sopenharmony_ci sizeof(inq_data)); 29208c2ecf20Sopenharmony_ci if (aac_wwn != 2) 29218c2ecf20Sopenharmony_ci return aac_get_container_serial( 29228c2ecf20Sopenharmony_ci scsicmd); 29238c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | 29248c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | 29258c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 29268c2ecf20Sopenharmony_ci } else if (scsicmd->cmnd[2] == 0x83) { 29278c2ecf20Sopenharmony_ci /* vpd page 0x83 - Device Identification Page */ 29288c2ecf20Sopenharmony_ci char *sno = (char *)&inq_data; 29298c2ecf20Sopenharmony_ci sno[3] = setinqserial(dev, &sno[4], 29308c2ecf20Sopenharmony_ci scmd_id(scsicmd)); 29318c2ecf20Sopenharmony_ci if (aac_wwn != 2) 29328c2ecf20Sopenharmony_ci return aac_get_container_serial( 29338c2ecf20Sopenharmony_ci scsicmd); 29348c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | 29358c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | 29368c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 29378c2ecf20Sopenharmony_ci } else { 29388c2ecf20Sopenharmony_ci /* vpd page not implemented */ 29398c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | 29408c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | 29418c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 29428c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 29438c2ecf20Sopenharmony_ci ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, 29448c2ecf20Sopenharmony_ci ASENCODE_NO_SENSE, 7, 2); 29458c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, 29468c2ecf20Sopenharmony_ci &dev->fsa_dev[cid].sense_data, 29478c2ecf20Sopenharmony_ci min_t(size_t, 29488c2ecf20Sopenharmony_ci sizeof(dev->fsa_dev[cid].sense_data), 29498c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 29508c2ecf20Sopenharmony_ci } 29518c2ecf20Sopenharmony_ci break; 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ 29548c2ecf20Sopenharmony_ci 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 */ 29558c2ecf20Sopenharmony_ci inq_data.inqd_len = 31; 29568c2ecf20Sopenharmony_ci /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ 29578c2ecf20Sopenharmony_ci inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ 29588c2ecf20Sopenharmony_ci /* 29598c2ecf20Sopenharmony_ci * Set the Vendor, Product, and Revision Level 29608c2ecf20Sopenharmony_ci * see: <vendor>.c i.e. aac.c 29618c2ecf20Sopenharmony_ci */ 29628c2ecf20Sopenharmony_ci if (cid == host->this_id) { 29638c2ecf20Sopenharmony_ci setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types)); 29648c2ecf20Sopenharmony_ci inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ 29658c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq_data, 29668c2ecf20Sopenharmony_ci sizeof(inq_data)); 29678c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 29688c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 29698c2ecf20Sopenharmony_ci break; 29708c2ecf20Sopenharmony_ci } 29718c2ecf20Sopenharmony_ci if (dev->in_reset) 29728c2ecf20Sopenharmony_ci return -1; 29738c2ecf20Sopenharmony_ci setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); 29748c2ecf20Sopenharmony_ci inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ 29758c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); 29768c2ecf20Sopenharmony_ci return aac_get_container_name(scsicmd); 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci case SERVICE_ACTION_IN_16: 29798c2ecf20Sopenharmony_ci if (!(dev->raw_io_interface) || 29808c2ecf20Sopenharmony_ci !(dev->raw_io_64) || 29818c2ecf20Sopenharmony_ci ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) 29828c2ecf20Sopenharmony_ci break; 29838c2ecf20Sopenharmony_ci { 29848c2ecf20Sopenharmony_ci u64 capacity; 29858c2ecf20Sopenharmony_ci char cp[13]; 29868c2ecf20Sopenharmony_ci unsigned int alloc_len; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); 29898c2ecf20Sopenharmony_ci capacity = fsa_dev_ptr[cid].size - 1; 29908c2ecf20Sopenharmony_ci cp[0] = (capacity >> 56) & 0xff; 29918c2ecf20Sopenharmony_ci cp[1] = (capacity >> 48) & 0xff; 29928c2ecf20Sopenharmony_ci cp[2] = (capacity >> 40) & 0xff; 29938c2ecf20Sopenharmony_ci cp[3] = (capacity >> 32) & 0xff; 29948c2ecf20Sopenharmony_ci cp[4] = (capacity >> 24) & 0xff; 29958c2ecf20Sopenharmony_ci cp[5] = (capacity >> 16) & 0xff; 29968c2ecf20Sopenharmony_ci cp[6] = (capacity >> 8) & 0xff; 29978c2ecf20Sopenharmony_ci cp[7] = (capacity >> 0) & 0xff; 29988c2ecf20Sopenharmony_ci cp[8] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff; 29998c2ecf20Sopenharmony_ci cp[9] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 30008c2ecf20Sopenharmony_ci cp[10] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 30018c2ecf20Sopenharmony_ci cp[11] = (fsa_dev_ptr[cid].block_size) & 0xff; 30028c2ecf20Sopenharmony_ci cp[12] = 0; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci alloc_len = ((scsicmd->cmnd[10] << 24) 30058c2ecf20Sopenharmony_ci + (scsicmd->cmnd[11] << 16) 30068c2ecf20Sopenharmony_ci + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci alloc_len = min_t(size_t, alloc_len, sizeof(cp)); 30098c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len); 30108c2ecf20Sopenharmony_ci if (alloc_len < scsi_bufflen(scsicmd)) 30118c2ecf20Sopenharmony_ci scsi_set_resid(scsicmd, 30128c2ecf20Sopenharmony_ci scsi_bufflen(scsicmd) - alloc_len); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci /* Do not cache partition table for arrays */ 30158c2ecf20Sopenharmony_ci scsicmd->device->removable = 1; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 30188c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 30198c2ecf20Sopenharmony_ci break; 30208c2ecf20Sopenharmony_ci } 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci case READ_CAPACITY: 30238c2ecf20Sopenharmony_ci { 30248c2ecf20Sopenharmony_ci u32 capacity; 30258c2ecf20Sopenharmony_ci char cp[8]; 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "READ CAPACITY command.\n")); 30288c2ecf20Sopenharmony_ci if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 30298c2ecf20Sopenharmony_ci capacity = fsa_dev_ptr[cid].size - 1; 30308c2ecf20Sopenharmony_ci else 30318c2ecf20Sopenharmony_ci capacity = (u32)-1; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci cp[0] = (capacity >> 24) & 0xff; 30348c2ecf20Sopenharmony_ci cp[1] = (capacity >> 16) & 0xff; 30358c2ecf20Sopenharmony_ci cp[2] = (capacity >> 8) & 0xff; 30368c2ecf20Sopenharmony_ci cp[3] = (capacity >> 0) & 0xff; 30378c2ecf20Sopenharmony_ci cp[4] = (fsa_dev_ptr[cid].block_size >> 24) & 0xff; 30388c2ecf20Sopenharmony_ci cp[5] = (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 30398c2ecf20Sopenharmony_ci cp[6] = (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 30408c2ecf20Sopenharmony_ci cp[7] = (fsa_dev_ptr[cid].block_size) & 0xff; 30418c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); 30428c2ecf20Sopenharmony_ci /* Do not cache partition table for arrays */ 30438c2ecf20Sopenharmony_ci scsicmd->device->removable = 1; 30448c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 30458c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 30468c2ecf20Sopenharmony_ci break; 30478c2ecf20Sopenharmony_ci } 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci case MODE_SENSE: 30508c2ecf20Sopenharmony_ci { 30518c2ecf20Sopenharmony_ci int mode_buf_length = 4; 30528c2ecf20Sopenharmony_ci u32 capacity; 30538c2ecf20Sopenharmony_ci aac_modep_data mpd; 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 30568c2ecf20Sopenharmony_ci capacity = fsa_dev_ptr[cid].size - 1; 30578c2ecf20Sopenharmony_ci else 30588c2ecf20Sopenharmony_ci capacity = (u32)-1; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "MODE SENSE command.\n")); 30618c2ecf20Sopenharmony_ci memset((char *)&mpd, 0, sizeof(aac_modep_data)); 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci /* Mode data length */ 30648c2ecf20Sopenharmony_ci mpd.hd.data_length = sizeof(mpd.hd) - 1; 30658c2ecf20Sopenharmony_ci /* Medium type - default */ 30668c2ecf20Sopenharmony_ci mpd.hd.med_type = 0; 30678c2ecf20Sopenharmony_ci /* Device-specific param, 30688c2ecf20Sopenharmony_ci bit 8: 0/1 = write enabled/protected 30698c2ecf20Sopenharmony_ci bit 4: 0/1 = FUA enabled */ 30708c2ecf20Sopenharmony_ci mpd.hd.dev_par = 0; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci if (dev->raw_io_interface && ((aac_cache & 5) != 1)) 30738c2ecf20Sopenharmony_ci mpd.hd.dev_par = 0x10; 30748c2ecf20Sopenharmony_ci if (scsicmd->cmnd[1] & 0x8) 30758c2ecf20Sopenharmony_ci mpd.hd.bd_length = 0; /* Block descriptor length */ 30768c2ecf20Sopenharmony_ci else { 30778c2ecf20Sopenharmony_ci mpd.hd.bd_length = sizeof(mpd.bd); 30788c2ecf20Sopenharmony_ci mpd.hd.data_length += mpd.hd.bd_length; 30798c2ecf20Sopenharmony_ci mpd.bd.block_length[0] = 30808c2ecf20Sopenharmony_ci (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 30818c2ecf20Sopenharmony_ci mpd.bd.block_length[1] = 30828c2ecf20Sopenharmony_ci (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 30838c2ecf20Sopenharmony_ci mpd.bd.block_length[2] = 30848c2ecf20Sopenharmony_ci fsa_dev_ptr[cid].block_size & 0xff; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci mpd.mpc_buf[0] = scsicmd->cmnd[2]; 30878c2ecf20Sopenharmony_ci if (scsicmd->cmnd[2] == 0x1C) { 30888c2ecf20Sopenharmony_ci /* page length */ 30898c2ecf20Sopenharmony_ci mpd.mpc_buf[1] = 0xa; 30908c2ecf20Sopenharmony_ci /* Mode data length */ 30918c2ecf20Sopenharmony_ci mpd.hd.data_length = 23; 30928c2ecf20Sopenharmony_ci } else { 30938c2ecf20Sopenharmony_ci /* Mode data length */ 30948c2ecf20Sopenharmony_ci mpd.hd.data_length = 15; 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci if (capacity > 0xffffff) { 30988c2ecf20Sopenharmony_ci mpd.bd.block_count[0] = 0xff; 30998c2ecf20Sopenharmony_ci mpd.bd.block_count[1] = 0xff; 31008c2ecf20Sopenharmony_ci mpd.bd.block_count[2] = 0xff; 31018c2ecf20Sopenharmony_ci } else { 31028c2ecf20Sopenharmony_ci mpd.bd.block_count[0] = (capacity >> 16) & 0xff; 31038c2ecf20Sopenharmony_ci mpd.bd.block_count[1] = (capacity >> 8) & 0xff; 31048c2ecf20Sopenharmony_ci mpd.bd.block_count[2] = capacity & 0xff; 31058c2ecf20Sopenharmony_ci } 31068c2ecf20Sopenharmony_ci } 31078c2ecf20Sopenharmony_ci if (((scsicmd->cmnd[2] & 0x3f) == 8) || 31088c2ecf20Sopenharmony_ci ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { 31098c2ecf20Sopenharmony_ci mpd.hd.data_length += 3; 31108c2ecf20Sopenharmony_ci mpd.mpc_buf[0] = 8; 31118c2ecf20Sopenharmony_ci mpd.mpc_buf[1] = 1; 31128c2ecf20Sopenharmony_ci mpd.mpc_buf[2] = ((aac_cache & 6) == 2) 31138c2ecf20Sopenharmony_ci ? 0 : 0x04; /* WCE */ 31148c2ecf20Sopenharmony_ci mode_buf_length = sizeof(mpd); 31158c2ecf20Sopenharmony_ci } 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci if (mode_buf_length > scsicmd->cmnd[4]) 31188c2ecf20Sopenharmony_ci mode_buf_length = scsicmd->cmnd[4]; 31198c2ecf20Sopenharmony_ci else 31208c2ecf20Sopenharmony_ci mode_buf_length = sizeof(mpd); 31218c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, 31228c2ecf20Sopenharmony_ci (char *)&mpd, 31238c2ecf20Sopenharmony_ci mode_buf_length); 31248c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 31258c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 31268c2ecf20Sopenharmony_ci break; 31278c2ecf20Sopenharmony_ci } 31288c2ecf20Sopenharmony_ci case MODE_SENSE_10: 31298c2ecf20Sopenharmony_ci { 31308c2ecf20Sopenharmony_ci u32 capacity; 31318c2ecf20Sopenharmony_ci int mode_buf_length = 8; 31328c2ecf20Sopenharmony_ci aac_modep10_data mpd10; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci if (fsa_dev_ptr[cid].size <= 0x100000000ULL) 31358c2ecf20Sopenharmony_ci capacity = fsa_dev_ptr[cid].size - 1; 31368c2ecf20Sopenharmony_ci else 31378c2ecf20Sopenharmony_ci capacity = (u32)-1; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); 31408c2ecf20Sopenharmony_ci memset((char *)&mpd10, 0, sizeof(aac_modep10_data)); 31418c2ecf20Sopenharmony_ci /* Mode data length (MSB) */ 31428c2ecf20Sopenharmony_ci mpd10.hd.data_length[0] = 0; 31438c2ecf20Sopenharmony_ci /* Mode data length (LSB) */ 31448c2ecf20Sopenharmony_ci mpd10.hd.data_length[1] = sizeof(mpd10.hd) - 1; 31458c2ecf20Sopenharmony_ci /* Medium type - default */ 31468c2ecf20Sopenharmony_ci mpd10.hd.med_type = 0; 31478c2ecf20Sopenharmony_ci /* Device-specific param, 31488c2ecf20Sopenharmony_ci bit 8: 0/1 = write enabled/protected 31498c2ecf20Sopenharmony_ci bit 4: 0/1 = FUA enabled */ 31508c2ecf20Sopenharmony_ci mpd10.hd.dev_par = 0; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci if (dev->raw_io_interface && ((aac_cache & 5) != 1)) 31538c2ecf20Sopenharmony_ci mpd10.hd.dev_par = 0x10; 31548c2ecf20Sopenharmony_ci mpd10.hd.rsrvd[0] = 0; /* reserved */ 31558c2ecf20Sopenharmony_ci mpd10.hd.rsrvd[1] = 0; /* reserved */ 31568c2ecf20Sopenharmony_ci if (scsicmd->cmnd[1] & 0x8) { 31578c2ecf20Sopenharmony_ci /* Block descriptor length (MSB) */ 31588c2ecf20Sopenharmony_ci mpd10.hd.bd_length[0] = 0; 31598c2ecf20Sopenharmony_ci /* Block descriptor length (LSB) */ 31608c2ecf20Sopenharmony_ci mpd10.hd.bd_length[1] = 0; 31618c2ecf20Sopenharmony_ci } else { 31628c2ecf20Sopenharmony_ci mpd10.hd.bd_length[0] = 0; 31638c2ecf20Sopenharmony_ci mpd10.hd.bd_length[1] = sizeof(mpd10.bd); 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci mpd10.hd.data_length[1] += mpd10.hd.bd_length[1]; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci mpd10.bd.block_length[0] = 31688c2ecf20Sopenharmony_ci (fsa_dev_ptr[cid].block_size >> 16) & 0xff; 31698c2ecf20Sopenharmony_ci mpd10.bd.block_length[1] = 31708c2ecf20Sopenharmony_ci (fsa_dev_ptr[cid].block_size >> 8) & 0xff; 31718c2ecf20Sopenharmony_ci mpd10.bd.block_length[2] = 31728c2ecf20Sopenharmony_ci fsa_dev_ptr[cid].block_size & 0xff; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci if (capacity > 0xffffff) { 31758c2ecf20Sopenharmony_ci mpd10.bd.block_count[0] = 0xff; 31768c2ecf20Sopenharmony_ci mpd10.bd.block_count[1] = 0xff; 31778c2ecf20Sopenharmony_ci mpd10.bd.block_count[2] = 0xff; 31788c2ecf20Sopenharmony_ci } else { 31798c2ecf20Sopenharmony_ci mpd10.bd.block_count[0] = 31808c2ecf20Sopenharmony_ci (capacity >> 16) & 0xff; 31818c2ecf20Sopenharmony_ci mpd10.bd.block_count[1] = 31828c2ecf20Sopenharmony_ci (capacity >> 8) & 0xff; 31838c2ecf20Sopenharmony_ci mpd10.bd.block_count[2] = 31848c2ecf20Sopenharmony_ci capacity & 0xff; 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci } 31878c2ecf20Sopenharmony_ci if (((scsicmd->cmnd[2] & 0x3f) == 8) || 31888c2ecf20Sopenharmony_ci ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { 31898c2ecf20Sopenharmony_ci mpd10.hd.data_length[1] += 3; 31908c2ecf20Sopenharmony_ci mpd10.mpc_buf[0] = 8; 31918c2ecf20Sopenharmony_ci mpd10.mpc_buf[1] = 1; 31928c2ecf20Sopenharmony_ci mpd10.mpc_buf[2] = ((aac_cache & 6) == 2) 31938c2ecf20Sopenharmony_ci ? 0 : 0x04; /* WCE */ 31948c2ecf20Sopenharmony_ci mode_buf_length = sizeof(mpd10); 31958c2ecf20Sopenharmony_ci if (mode_buf_length > scsicmd->cmnd[8]) 31968c2ecf20Sopenharmony_ci mode_buf_length = scsicmd->cmnd[8]; 31978c2ecf20Sopenharmony_ci } 31988c2ecf20Sopenharmony_ci scsi_sg_copy_from_buffer(scsicmd, 31998c2ecf20Sopenharmony_ci (char *)&mpd10, 32008c2ecf20Sopenharmony_ci mode_buf_length); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32038c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 32048c2ecf20Sopenharmony_ci break; 32058c2ecf20Sopenharmony_ci } 32068c2ecf20Sopenharmony_ci case REQUEST_SENSE: 32078c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); 32088c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 32098c2ecf20Sopenharmony_ci sizeof(struct sense_data)); 32108c2ecf20Sopenharmony_ci memset(&dev->fsa_dev[cid].sense_data, 0, 32118c2ecf20Sopenharmony_ci sizeof(struct sense_data)); 32128c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32138c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 32148c2ecf20Sopenharmony_ci break; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci case ALLOW_MEDIUM_REMOVAL: 32178c2ecf20Sopenharmony_ci dprintk((KERN_DEBUG "LOCK command.\n")); 32188c2ecf20Sopenharmony_ci if (scsicmd->cmnd[4]) 32198c2ecf20Sopenharmony_ci fsa_dev_ptr[cid].locked = 1; 32208c2ecf20Sopenharmony_ci else 32218c2ecf20Sopenharmony_ci fsa_dev_ptr[cid].locked = 0; 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32248c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 32258c2ecf20Sopenharmony_ci break; 32268c2ecf20Sopenharmony_ci /* 32278c2ecf20Sopenharmony_ci * These commands are all No-Ops 32288c2ecf20Sopenharmony_ci */ 32298c2ecf20Sopenharmony_ci case TEST_UNIT_READY: 32308c2ecf20Sopenharmony_ci if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) { 32318c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32328c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 32338c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 32348c2ecf20Sopenharmony_ci NOT_READY, SENCODE_BECOMING_READY, 32358c2ecf20Sopenharmony_ci ASENCODE_BECOMING_READY, 0, 0); 32368c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, 32378c2ecf20Sopenharmony_ci &dev->fsa_dev[cid].sense_data, 32388c2ecf20Sopenharmony_ci min_t(size_t, 32398c2ecf20Sopenharmony_ci sizeof(dev->fsa_dev[cid].sense_data), 32408c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 32418c2ecf20Sopenharmony_ci break; 32428c2ecf20Sopenharmony_ci } 32438c2ecf20Sopenharmony_ci fallthrough; 32448c2ecf20Sopenharmony_ci case RESERVE: 32458c2ecf20Sopenharmony_ci case RELEASE: 32468c2ecf20Sopenharmony_ci case REZERO_UNIT: 32478c2ecf20Sopenharmony_ci case REASSIGN_BLOCKS: 32488c2ecf20Sopenharmony_ci case SEEK_10: 32498c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32508c2ecf20Sopenharmony_ci SAM_STAT_GOOD; 32518c2ecf20Sopenharmony_ci break; 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci case START_STOP: 32548c2ecf20Sopenharmony_ci return aac_start_stop(scsicmd); 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci default: 32578c2ecf20Sopenharmony_ci /* 32588c2ecf20Sopenharmony_ci * Unhandled commands 32598c2ecf20Sopenharmony_ci */ 32608c2ecf20Sopenharmony_ci dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", 32618c2ecf20Sopenharmony_ci scsicmd->cmnd[0])); 32628c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 32638c2ecf20Sopenharmony_ci SAM_STAT_CHECK_CONDITION; 32648c2ecf20Sopenharmony_ci set_sense(&dev->fsa_dev[cid].sense_data, 32658c2ecf20Sopenharmony_ci ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, 32668c2ecf20Sopenharmony_ci ASENCODE_INVALID_COMMAND, 0, 0); 32678c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 32688c2ecf20Sopenharmony_ci min_t(size_t, 32698c2ecf20Sopenharmony_ci sizeof(dev->fsa_dev[cid].sense_data), 32708c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 32718c2ecf20Sopenharmony_ci } 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ciscsi_done_ret: 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 32768c2ecf20Sopenharmony_ci return 0; 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_cistatic int query_disk(struct aac_dev *dev, void __user *arg) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci struct aac_query_disk qd; 32828c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci fsa_dev_ptr = dev->fsa_dev; 32858c2ecf20Sopenharmony_ci if (!fsa_dev_ptr) 32868c2ecf20Sopenharmony_ci return -EBUSY; 32878c2ecf20Sopenharmony_ci if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) 32888c2ecf20Sopenharmony_ci return -EFAULT; 32898c2ecf20Sopenharmony_ci if (qd.cnum == -1) { 32908c2ecf20Sopenharmony_ci if (qd.id < 0 || qd.id >= dev->maximum_num_containers) 32918c2ecf20Sopenharmony_ci return -EINVAL; 32928c2ecf20Sopenharmony_ci qd.cnum = qd.id; 32938c2ecf20Sopenharmony_ci } else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) { 32948c2ecf20Sopenharmony_ci if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) 32958c2ecf20Sopenharmony_ci return -EINVAL; 32968c2ecf20Sopenharmony_ci qd.instance = dev->scsi_host_ptr->host_no; 32978c2ecf20Sopenharmony_ci qd.bus = 0; 32988c2ecf20Sopenharmony_ci qd.id = CONTAINER_TO_ID(qd.cnum); 32998c2ecf20Sopenharmony_ci qd.lun = CONTAINER_TO_LUN(qd.cnum); 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci else return -EINVAL; 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci qd.valid = fsa_dev_ptr[qd.cnum].valid != 0; 33048c2ecf20Sopenharmony_ci qd.locked = fsa_dev_ptr[qd.cnum].locked; 33058c2ecf20Sopenharmony_ci qd.deleted = fsa_dev_ptr[qd.cnum].deleted; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci if (fsa_dev_ptr[qd.cnum].devname[0] == '\0') 33088c2ecf20Sopenharmony_ci qd.unmapped = 1; 33098c2ecf20Sopenharmony_ci else 33108c2ecf20Sopenharmony_ci qd.unmapped = 0; 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname, 33138c2ecf20Sopenharmony_ci min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1)); 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) 33168c2ecf20Sopenharmony_ci return -EFAULT; 33178c2ecf20Sopenharmony_ci return 0; 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_cistatic int force_delete_disk(struct aac_dev *dev, void __user *arg) 33218c2ecf20Sopenharmony_ci{ 33228c2ecf20Sopenharmony_ci struct aac_delete_disk dd; 33238c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci fsa_dev_ptr = dev->fsa_dev; 33268c2ecf20Sopenharmony_ci if (!fsa_dev_ptr) 33278c2ecf20Sopenharmony_ci return -EBUSY; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) 33308c2ecf20Sopenharmony_ci return -EFAULT; 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci if (dd.cnum >= dev->maximum_num_containers) 33338c2ecf20Sopenharmony_ci return -EINVAL; 33348c2ecf20Sopenharmony_ci /* 33358c2ecf20Sopenharmony_ci * Mark this container as being deleted. 33368c2ecf20Sopenharmony_ci */ 33378c2ecf20Sopenharmony_ci fsa_dev_ptr[dd.cnum].deleted = 1; 33388c2ecf20Sopenharmony_ci /* 33398c2ecf20Sopenharmony_ci * Mark the container as no longer valid 33408c2ecf20Sopenharmony_ci */ 33418c2ecf20Sopenharmony_ci fsa_dev_ptr[dd.cnum].valid = 0; 33428c2ecf20Sopenharmony_ci return 0; 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cistatic int delete_disk(struct aac_dev *dev, void __user *arg) 33468c2ecf20Sopenharmony_ci{ 33478c2ecf20Sopenharmony_ci struct aac_delete_disk dd; 33488c2ecf20Sopenharmony_ci struct fsa_dev_info *fsa_dev_ptr; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci fsa_dev_ptr = dev->fsa_dev; 33518c2ecf20Sopenharmony_ci if (!fsa_dev_ptr) 33528c2ecf20Sopenharmony_ci return -EBUSY; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) 33558c2ecf20Sopenharmony_ci return -EFAULT; 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci if (dd.cnum >= dev->maximum_num_containers) 33588c2ecf20Sopenharmony_ci return -EINVAL; 33598c2ecf20Sopenharmony_ci /* 33608c2ecf20Sopenharmony_ci * If the container is locked, it can not be deleted by the API. 33618c2ecf20Sopenharmony_ci */ 33628c2ecf20Sopenharmony_ci if (fsa_dev_ptr[dd.cnum].locked) 33638c2ecf20Sopenharmony_ci return -EBUSY; 33648c2ecf20Sopenharmony_ci else { 33658c2ecf20Sopenharmony_ci /* 33668c2ecf20Sopenharmony_ci * Mark the container as no longer being valid. 33678c2ecf20Sopenharmony_ci */ 33688c2ecf20Sopenharmony_ci fsa_dev_ptr[dd.cnum].valid = 0; 33698c2ecf20Sopenharmony_ci fsa_dev_ptr[dd.cnum].devname[0] = '\0'; 33708c2ecf20Sopenharmony_ci return 0; 33718c2ecf20Sopenharmony_ci } 33728c2ecf20Sopenharmony_ci} 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ciint aac_dev_ioctl(struct aac_dev *dev, unsigned int cmd, void __user *arg) 33758c2ecf20Sopenharmony_ci{ 33768c2ecf20Sopenharmony_ci switch (cmd) { 33778c2ecf20Sopenharmony_ci case FSACTL_QUERY_DISK: 33788c2ecf20Sopenharmony_ci return query_disk(dev, arg); 33798c2ecf20Sopenharmony_ci case FSACTL_DELETE_DISK: 33808c2ecf20Sopenharmony_ci return delete_disk(dev, arg); 33818c2ecf20Sopenharmony_ci case FSACTL_FORCE_DELETE_DISK: 33828c2ecf20Sopenharmony_ci return force_delete_disk(dev, arg); 33838c2ecf20Sopenharmony_ci case FSACTL_GET_CONTAINERS: 33848c2ecf20Sopenharmony_ci return aac_get_containers(dev); 33858c2ecf20Sopenharmony_ci default: 33868c2ecf20Sopenharmony_ci return -ENOTTY; 33878c2ecf20Sopenharmony_ci } 33888c2ecf20Sopenharmony_ci} 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci/** 33918c2ecf20Sopenharmony_ci * aac_srb_callback 33928c2ecf20Sopenharmony_ci * @context: the context set in the fib - here it is scsi cmd 33938c2ecf20Sopenharmony_ci * @fibptr: pointer to the fib 33948c2ecf20Sopenharmony_ci * 33958c2ecf20Sopenharmony_ci * Handles the completion of a scsi command to a non dasd device 33968c2ecf20Sopenharmony_ci */ 33978c2ecf20Sopenharmony_cistatic void aac_srb_callback(void *context, struct fib * fibptr) 33988c2ecf20Sopenharmony_ci{ 33998c2ecf20Sopenharmony_ci struct aac_srb_reply *srbreply; 34008c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 34058c2ecf20Sopenharmony_ci return; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci BUG_ON(fibptr == NULL); 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci srbreply = (struct aac_srb_reply *) fib_data(fibptr); 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { 34148c2ecf20Sopenharmony_ci /* fast response */ 34158c2ecf20Sopenharmony_ci srbreply->srb_status = cpu_to_le32(SRB_STATUS_SUCCESS); 34168c2ecf20Sopenharmony_ci srbreply->scsi_status = cpu_to_le32(SAM_STAT_GOOD); 34178c2ecf20Sopenharmony_ci } else { 34188c2ecf20Sopenharmony_ci /* 34198c2ecf20Sopenharmony_ci * Calculate resid for sg 34208c2ecf20Sopenharmony_ci */ 34218c2ecf20Sopenharmony_ci scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) 34228c2ecf20Sopenharmony_ci - le32_to_cpu(srbreply->data_xfer_length)); 34238c2ecf20Sopenharmony_ci } 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci scsi_dma_unmap(scsicmd); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci /* expose physical device if expose_physicald flag is on */ 34298c2ecf20Sopenharmony_ci if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) 34308c2ecf20Sopenharmony_ci && expose_physicals > 0) 34318c2ecf20Sopenharmony_ci aac_expose_phy_device(scsicmd); 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci /* 34348c2ecf20Sopenharmony_ci * First check the fib status 34358c2ecf20Sopenharmony_ci */ 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci if (le32_to_cpu(srbreply->status) != ST_OK) { 34388c2ecf20Sopenharmony_ci int len; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci pr_warn("aac_srb_callback: srb failed, status = %d\n", 34418c2ecf20Sopenharmony_ci le32_to_cpu(srbreply->status)); 34428c2ecf20Sopenharmony_ci len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), 34438c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 34448c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 34458c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8 34468c2ecf20Sopenharmony_ci | SAM_STAT_CHECK_CONDITION; 34478c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, 34488c2ecf20Sopenharmony_ci srbreply->sense_data, len); 34498c2ecf20Sopenharmony_ci } 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci /* 34528c2ecf20Sopenharmony_ci * Next check the srb status 34538c2ecf20Sopenharmony_ci */ 34548c2ecf20Sopenharmony_ci switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { 34558c2ecf20Sopenharmony_ci case SRB_STATUS_ERROR_RECOVERY: 34568c2ecf20Sopenharmony_ci case SRB_STATUS_PENDING: 34578c2ecf20Sopenharmony_ci case SRB_STATUS_SUCCESS: 34588c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 34598c2ecf20Sopenharmony_ci break; 34608c2ecf20Sopenharmony_ci case SRB_STATUS_DATA_OVERRUN: 34618c2ecf20Sopenharmony_ci switch (scsicmd->cmnd[0]) { 34628c2ecf20Sopenharmony_ci case READ_6: 34638c2ecf20Sopenharmony_ci case WRITE_6: 34648c2ecf20Sopenharmony_ci case READ_10: 34658c2ecf20Sopenharmony_ci case WRITE_10: 34668c2ecf20Sopenharmony_ci case READ_12: 34678c2ecf20Sopenharmony_ci case WRITE_12: 34688c2ecf20Sopenharmony_ci case READ_16: 34698c2ecf20Sopenharmony_ci case WRITE_16: 34708c2ecf20Sopenharmony_ci if (le32_to_cpu(srbreply->data_xfer_length) 34718c2ecf20Sopenharmony_ci < scsicmd->underflow) 34728c2ecf20Sopenharmony_ci pr_warn("aacraid: SCSI CMD underflow\n"); 34738c2ecf20Sopenharmony_ci else 34748c2ecf20Sopenharmony_ci pr_warn("aacraid: SCSI CMD Data Overrun\n"); 34758c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 34768c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 34778c2ecf20Sopenharmony_ci break; 34788c2ecf20Sopenharmony_ci case INQUIRY: 34798c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 34808c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 34818c2ecf20Sopenharmony_ci break; 34828c2ecf20Sopenharmony_ci default: 34838c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 34848c2ecf20Sopenharmony_ci break; 34858c2ecf20Sopenharmony_ci } 34868c2ecf20Sopenharmony_ci break; 34878c2ecf20Sopenharmony_ci case SRB_STATUS_ABORTED: 34888c2ecf20Sopenharmony_ci scsicmd->result = DID_ABORT << 16 | ABORT << 8; 34898c2ecf20Sopenharmony_ci break; 34908c2ecf20Sopenharmony_ci case SRB_STATUS_ABORT_FAILED: 34918c2ecf20Sopenharmony_ci /* 34928c2ecf20Sopenharmony_ci * Not sure about this one - but assuming the 34938c2ecf20Sopenharmony_ci * hba was trying to abort for some reason 34948c2ecf20Sopenharmony_ci */ 34958c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 | ABORT << 8; 34968c2ecf20Sopenharmony_ci break; 34978c2ecf20Sopenharmony_ci case SRB_STATUS_PARITY_ERROR: 34988c2ecf20Sopenharmony_ci scsicmd->result = DID_PARITY << 16 34998c2ecf20Sopenharmony_ci | MSG_PARITY_ERROR << 8; 35008c2ecf20Sopenharmony_ci break; 35018c2ecf20Sopenharmony_ci case SRB_STATUS_NO_DEVICE: 35028c2ecf20Sopenharmony_ci case SRB_STATUS_INVALID_PATH_ID: 35038c2ecf20Sopenharmony_ci case SRB_STATUS_INVALID_TARGET_ID: 35048c2ecf20Sopenharmony_ci case SRB_STATUS_INVALID_LUN: 35058c2ecf20Sopenharmony_ci case SRB_STATUS_SELECTION_TIMEOUT: 35068c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16 35078c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35088c2ecf20Sopenharmony_ci break; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci case SRB_STATUS_COMMAND_TIMEOUT: 35118c2ecf20Sopenharmony_ci case SRB_STATUS_TIMEOUT: 35128c2ecf20Sopenharmony_ci scsicmd->result = DID_TIME_OUT << 16 35138c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35148c2ecf20Sopenharmony_ci break; 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci case SRB_STATUS_BUSY: 35178c2ecf20Sopenharmony_ci scsicmd->result = DID_BUS_BUSY << 16 35188c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35198c2ecf20Sopenharmony_ci break; 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci case SRB_STATUS_BUS_RESET: 35228c2ecf20Sopenharmony_ci scsicmd->result = DID_RESET << 16 35238c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35248c2ecf20Sopenharmony_ci break; 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci case SRB_STATUS_MESSAGE_REJECTED: 35278c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 35288c2ecf20Sopenharmony_ci | MESSAGE_REJECT << 8; 35298c2ecf20Sopenharmony_ci break; 35308c2ecf20Sopenharmony_ci case SRB_STATUS_REQUEST_FLUSHED: 35318c2ecf20Sopenharmony_ci case SRB_STATUS_ERROR: 35328c2ecf20Sopenharmony_ci case SRB_STATUS_INVALID_REQUEST: 35338c2ecf20Sopenharmony_ci case SRB_STATUS_REQUEST_SENSE_FAILED: 35348c2ecf20Sopenharmony_ci case SRB_STATUS_NO_HBA: 35358c2ecf20Sopenharmony_ci case SRB_STATUS_UNEXPECTED_BUS_FREE: 35368c2ecf20Sopenharmony_ci case SRB_STATUS_PHASE_SEQUENCE_FAILURE: 35378c2ecf20Sopenharmony_ci case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: 35388c2ecf20Sopenharmony_ci case SRB_STATUS_DELAYED_RETRY: 35398c2ecf20Sopenharmony_ci case SRB_STATUS_BAD_FUNCTION: 35408c2ecf20Sopenharmony_ci case SRB_STATUS_NOT_STARTED: 35418c2ecf20Sopenharmony_ci case SRB_STATUS_NOT_IN_USE: 35428c2ecf20Sopenharmony_ci case SRB_STATUS_FORCE_ABORT: 35438c2ecf20Sopenharmony_ci case SRB_STATUS_DOMAIN_VALIDATION_FAIL: 35448c2ecf20Sopenharmony_ci default: 35458c2ecf20Sopenharmony_ci#ifdef AAC_DETAILED_STATUS_INFO 35468c2ecf20Sopenharmony_ci pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n", 35478c2ecf20Sopenharmony_ci le32_to_cpu(srbreply->srb_status) & 0x3F, 35488c2ecf20Sopenharmony_ci aac_get_status_string( 35498c2ecf20Sopenharmony_ci le32_to_cpu(srbreply->srb_status) & 0x3F), 35508c2ecf20Sopenharmony_ci scsicmd->cmnd[0], 35518c2ecf20Sopenharmony_ci le32_to_cpu(srbreply->scsi_status)); 35528c2ecf20Sopenharmony_ci#endif 35538c2ecf20Sopenharmony_ci /* 35548c2ecf20Sopenharmony_ci * When the CC bit is SET by the host in ATA pass thru CDB, 35558c2ecf20Sopenharmony_ci * driver is supposed to return DID_OK 35568c2ecf20Sopenharmony_ci * 35578c2ecf20Sopenharmony_ci * When the CC bit is RESET by the host, driver should 35588c2ecf20Sopenharmony_ci * return DID_ERROR 35598c2ecf20Sopenharmony_ci */ 35608c2ecf20Sopenharmony_ci if ((scsicmd->cmnd[0] == ATA_12) 35618c2ecf20Sopenharmony_ci || (scsicmd->cmnd[0] == ATA_16)) { 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci if (scsicmd->cmnd[2] & (0x01 << 5)) { 35648c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 35658c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35668c2ecf20Sopenharmony_ci break; 35678c2ecf20Sopenharmony_ci } else { 35688c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 35698c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35708c2ecf20Sopenharmony_ci break; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci } else { 35738c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 35748c2ecf20Sopenharmony_ci | COMMAND_COMPLETE << 8; 35758c2ecf20Sopenharmony_ci break; 35768c2ecf20Sopenharmony_ci } 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci if (le32_to_cpu(srbreply->scsi_status) 35798c2ecf20Sopenharmony_ci == SAM_STAT_CHECK_CONDITION) { 35808c2ecf20Sopenharmony_ci int len; 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci scsicmd->result |= SAM_STAT_CHECK_CONDITION; 35838c2ecf20Sopenharmony_ci len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), 35848c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 35858c2ecf20Sopenharmony_ci#ifdef AAC_DETAILED_STATUS_INFO 35868c2ecf20Sopenharmony_ci pr_warn("aac_srb_callback: check condition, status = %d len=%d\n", 35878c2ecf20Sopenharmony_ci le32_to_cpu(srbreply->status), len); 35888c2ecf20Sopenharmony_ci#endif 35898c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, 35908c2ecf20Sopenharmony_ci srbreply->sense_data, len); 35918c2ecf20Sopenharmony_ci } 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci /* 35948c2ecf20Sopenharmony_ci * OR in the scsi status (already shifted up a bit) 35958c2ecf20Sopenharmony_ci */ 35968c2ecf20Sopenharmony_ci scsicmd->result |= le32_to_cpu(srbreply->scsi_status); 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 35998c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 36008c2ecf20Sopenharmony_ci} 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_cistatic void hba_resp_task_complete(struct aac_dev *dev, 36038c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd, 36048c2ecf20Sopenharmony_ci struct aac_hba_resp *err) { 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci scsicmd->result = err->status; 36078c2ecf20Sopenharmony_ci /* set residual count */ 36088c2ecf20Sopenharmony_ci scsi_set_resid(scsicmd, le32_to_cpu(err->residual_count)); 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci switch (err->status) { 36118c2ecf20Sopenharmony_ci case SAM_STAT_GOOD: 36128c2ecf20Sopenharmony_ci scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; 36138c2ecf20Sopenharmony_ci break; 36148c2ecf20Sopenharmony_ci case SAM_STAT_CHECK_CONDITION: 36158c2ecf20Sopenharmony_ci { 36168c2ecf20Sopenharmony_ci int len; 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci len = min_t(u8, err->sense_response_data_len, 36198c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 36208c2ecf20Sopenharmony_ci if (len) 36218c2ecf20Sopenharmony_ci memcpy(scsicmd->sense_buffer, 36228c2ecf20Sopenharmony_ci err->sense_response_buf, len); 36238c2ecf20Sopenharmony_ci scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; 36248c2ecf20Sopenharmony_ci break; 36258c2ecf20Sopenharmony_ci } 36268c2ecf20Sopenharmony_ci case SAM_STAT_BUSY: 36278c2ecf20Sopenharmony_ci scsicmd->result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; 36288c2ecf20Sopenharmony_ci break; 36298c2ecf20Sopenharmony_ci case SAM_STAT_TASK_ABORTED: 36308c2ecf20Sopenharmony_ci scsicmd->result |= DID_ABORT << 16 | ABORT << 8; 36318c2ecf20Sopenharmony_ci break; 36328c2ecf20Sopenharmony_ci case SAM_STAT_RESERVATION_CONFLICT: 36338c2ecf20Sopenharmony_ci case SAM_STAT_TASK_SET_FULL: 36348c2ecf20Sopenharmony_ci default: 36358c2ecf20Sopenharmony_ci scsicmd->result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8; 36368c2ecf20Sopenharmony_ci break; 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci} 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_cistatic void hba_resp_task_failure(struct aac_dev *dev, 36418c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd, 36428c2ecf20Sopenharmony_ci struct aac_hba_resp *err) 36438c2ecf20Sopenharmony_ci{ 36448c2ecf20Sopenharmony_ci switch (err->status) { 36458c2ecf20Sopenharmony_ci case HBA_RESP_STAT_HBAMODE_DISABLED: 36468c2ecf20Sopenharmony_ci { 36478c2ecf20Sopenharmony_ci u32 bus, cid; 36488c2ecf20Sopenharmony_ci 36498c2ecf20Sopenharmony_ci bus = aac_logical_to_phys(scmd_channel(scsicmd)); 36508c2ecf20Sopenharmony_ci cid = scmd_id(scsicmd); 36518c2ecf20Sopenharmony_ci if (dev->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { 36528c2ecf20Sopenharmony_ci dev->hba_map[bus][cid].devtype = AAC_DEVTYPE_ARC_RAW; 36538c2ecf20Sopenharmony_ci dev->hba_map[bus][cid].rmw_nexus = 0xffffffff; 36548c2ecf20Sopenharmony_ci } 36558c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 36568c2ecf20Sopenharmony_ci break; 36578c2ecf20Sopenharmony_ci } 36588c2ecf20Sopenharmony_ci case HBA_RESP_STAT_IO_ERROR: 36598c2ecf20Sopenharmony_ci case HBA_RESP_STAT_NO_PATH_TO_DEVICE: 36608c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | 36618c2ecf20Sopenharmony_ci COMMAND_COMPLETE << 8 | SAM_STAT_BUSY; 36628c2ecf20Sopenharmony_ci break; 36638c2ecf20Sopenharmony_ci case HBA_RESP_STAT_IO_ABORTED: 36648c2ecf20Sopenharmony_ci scsicmd->result = DID_ABORT << 16 | ABORT << 8; 36658c2ecf20Sopenharmony_ci break; 36668c2ecf20Sopenharmony_ci case HBA_RESP_STAT_INVALID_DEVICE: 36678c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 36688c2ecf20Sopenharmony_ci break; 36698c2ecf20Sopenharmony_ci case HBA_RESP_STAT_UNDERRUN: 36708c2ecf20Sopenharmony_ci /* UNDERRUN is OK */ 36718c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 36728c2ecf20Sopenharmony_ci break; 36738c2ecf20Sopenharmony_ci case HBA_RESP_STAT_OVERRUN: 36748c2ecf20Sopenharmony_ci default: 36758c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; 36768c2ecf20Sopenharmony_ci break; 36778c2ecf20Sopenharmony_ci } 36788c2ecf20Sopenharmony_ci} 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci/** 36818c2ecf20Sopenharmony_ci * aac_hba_callback 36828c2ecf20Sopenharmony_ci * @context: the context set in the fib - here it is scsi cmd 36838c2ecf20Sopenharmony_ci * @fibptr: pointer to the fib 36848c2ecf20Sopenharmony_ci * 36858c2ecf20Sopenharmony_ci * Handles the completion of a native HBA scsi command 36868c2ecf20Sopenharmony_ci */ 36878c2ecf20Sopenharmony_civoid aac_hba_callback(void *context, struct fib *fibptr) 36888c2ecf20Sopenharmony_ci{ 36898c2ecf20Sopenharmony_ci struct aac_dev *dev; 36908c2ecf20Sopenharmony_ci struct scsi_cmnd *scsicmd; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci struct aac_hba_resp *err = 36938c2ecf20Sopenharmony_ci &((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err; 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci scsicmd = (struct scsi_cmnd *) context; 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci if (!aac_valid_context(scsicmd, fibptr)) 36988c2ecf20Sopenharmony_ci return; 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci WARN_ON(fibptr == NULL); 37018c2ecf20Sopenharmony_ci dev = fibptr->dev; 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF)) 37048c2ecf20Sopenharmony_ci scsi_dma_unmap(scsicmd); 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { 37078c2ecf20Sopenharmony_ci /* fast response */ 37088c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 37098c2ecf20Sopenharmony_ci goto out; 37108c2ecf20Sopenharmony_ci } 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci switch (err->service_response) { 37138c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_TASK_COMPLETE: 37148c2ecf20Sopenharmony_ci hba_resp_task_complete(dev, scsicmd, err); 37158c2ecf20Sopenharmony_ci break; 37168c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_FAILURE: 37178c2ecf20Sopenharmony_ci hba_resp_task_failure(dev, scsicmd, err); 37188c2ecf20Sopenharmony_ci break; 37198c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_TMF_REJECTED: 37208c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; 37218c2ecf20Sopenharmony_ci break; 37228c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_TMF_LUN_INVALID: 37238c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; 37248c2ecf20Sopenharmony_ci break; 37258c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_TMF_COMPLETE: 37268c2ecf20Sopenharmony_ci case HBA_RESP_SVCRES_TMF_SUCCEEDED: 37278c2ecf20Sopenharmony_ci scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; 37288c2ecf20Sopenharmony_ci break; 37298c2ecf20Sopenharmony_ci default: 37308c2ecf20Sopenharmony_ci scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; 37318c2ecf20Sopenharmony_ci break; 37328c2ecf20Sopenharmony_ci } 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ciout: 37358c2ecf20Sopenharmony_ci aac_fib_complete(fibptr); 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) 37388c2ecf20Sopenharmony_ci scsicmd->SCp.sent_command = 1; 37398c2ecf20Sopenharmony_ci else 37408c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 37418c2ecf20Sopenharmony_ci} 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci/** 37448c2ecf20Sopenharmony_ci * aac_send_srb_fib 37458c2ecf20Sopenharmony_ci * @scsicmd: the scsi command block 37468c2ecf20Sopenharmony_ci * 37478c2ecf20Sopenharmony_ci * This routine will form a FIB and fill in the aac_srb from the 37488c2ecf20Sopenharmony_ci * scsicmd passed in. 37498c2ecf20Sopenharmony_ci */ 37508c2ecf20Sopenharmony_cistatic int aac_send_srb_fib(struct scsi_cmnd* scsicmd) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci struct fib* cmd_fibcontext; 37538c2ecf20Sopenharmony_ci struct aac_dev* dev; 37548c2ecf20Sopenharmony_ci int status; 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci dev = (struct aac_dev *)scsicmd->device->host->hostdata; 37578c2ecf20Sopenharmony_ci if (scmd_id(scsicmd) >= dev->maximum_num_physicals || 37588c2ecf20Sopenharmony_ci scsicmd->device->lun > 7) { 37598c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16; 37608c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 37618c2ecf20Sopenharmony_ci return 0; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci /* 37658c2ecf20Sopenharmony_ci * Allocate and initialize a Fib then setup a BlockWrite command 37668c2ecf20Sopenharmony_ci */ 37678c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 37688c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 37698c2ecf20Sopenharmony_ci status = aac_adapter_scsi(cmd_fibcontext, scsicmd); 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci /* 37728c2ecf20Sopenharmony_ci * Check that the command queued to the controller 37738c2ecf20Sopenharmony_ci */ 37748c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 37758c2ecf20Sopenharmony_ci return 0; 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status); 37788c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 37798c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci return -1; 37828c2ecf20Sopenharmony_ci} 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci/** 37858c2ecf20Sopenharmony_ci * aac_send_hba_fib 37868c2ecf20Sopenharmony_ci * @scsicmd: the scsi command block 37878c2ecf20Sopenharmony_ci * 37888c2ecf20Sopenharmony_ci * This routine will form a FIB and fill in the aac_hba_cmd_req from the 37898c2ecf20Sopenharmony_ci * scsicmd passed in. 37908c2ecf20Sopenharmony_ci */ 37918c2ecf20Sopenharmony_cistatic int aac_send_hba_fib(struct scsi_cmnd *scsicmd) 37928c2ecf20Sopenharmony_ci{ 37938c2ecf20Sopenharmony_ci struct fib *cmd_fibcontext; 37948c2ecf20Sopenharmony_ci struct aac_dev *dev; 37958c2ecf20Sopenharmony_ci int status; 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci dev = shost_priv(scsicmd->device->host); 37988c2ecf20Sopenharmony_ci if (scmd_id(scsicmd) >= dev->maximum_num_physicals || 37998c2ecf20Sopenharmony_ci scsicmd->device->lun > AAC_MAX_LUN - 1) { 38008c2ecf20Sopenharmony_ci scsicmd->result = DID_NO_CONNECT << 16; 38018c2ecf20Sopenharmony_ci scsicmd->scsi_done(scsicmd); 38028c2ecf20Sopenharmony_ci return 0; 38038c2ecf20Sopenharmony_ci } 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci /* 38068c2ecf20Sopenharmony_ci * Allocate and initialize a Fib then setup a BlockWrite command 38078c2ecf20Sopenharmony_ci */ 38088c2ecf20Sopenharmony_ci cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); 38098c2ecf20Sopenharmony_ci if (!cmd_fibcontext) 38108c2ecf20Sopenharmony_ci return -1; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; 38138c2ecf20Sopenharmony_ci status = aac_adapter_hba(cmd_fibcontext, scsicmd); 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci /* 38168c2ecf20Sopenharmony_ci * Check that the command queued to the controller 38178c2ecf20Sopenharmony_ci */ 38188c2ecf20Sopenharmony_ci if (status == -EINPROGRESS) 38198c2ecf20Sopenharmony_ci return 0; 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ci pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n", 38228c2ecf20Sopenharmony_ci status); 38238c2ecf20Sopenharmony_ci aac_fib_complete(cmd_fibcontext); 38248c2ecf20Sopenharmony_ci aac_fib_free(cmd_fibcontext); 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci return -1; 38278c2ecf20Sopenharmony_ci} 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_cistatic long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) 38318c2ecf20Sopenharmony_ci{ 38328c2ecf20Sopenharmony_ci unsigned long byte_count = 0; 38338c2ecf20Sopenharmony_ci int nseg; 38348c2ecf20Sopenharmony_ci struct scatterlist *sg; 38358c2ecf20Sopenharmony_ci int i; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci // Get rid of old data 38388c2ecf20Sopenharmony_ci psg->count = 0; 38398c2ecf20Sopenharmony_ci psg->sg[0].addr = 0; 38408c2ecf20Sopenharmony_ci psg->sg[0].count = 0; 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci nseg = scsi_dma_map(scsicmd); 38438c2ecf20Sopenharmony_ci if (nseg <= 0) 38448c2ecf20Sopenharmony_ci return nseg; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci psg->count = cpu_to_le32(nseg); 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci scsi_for_each_sg(scsicmd, sg, nseg, i) { 38498c2ecf20Sopenharmony_ci psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); 38508c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); 38518c2ecf20Sopenharmony_ci byte_count += sg_dma_len(sg); 38528c2ecf20Sopenharmony_ci } 38538c2ecf20Sopenharmony_ci /* hba wants the size to be exact */ 38548c2ecf20Sopenharmony_ci if (byte_count > scsi_bufflen(scsicmd)) { 38558c2ecf20Sopenharmony_ci u32 temp = le32_to_cpu(psg->sg[i-1].count) - 38568c2ecf20Sopenharmony_ci (byte_count - scsi_bufflen(scsicmd)); 38578c2ecf20Sopenharmony_ci psg->sg[i-1].count = cpu_to_le32(temp); 38588c2ecf20Sopenharmony_ci byte_count = scsi_bufflen(scsicmd); 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci /* Check for command underflow */ 38618c2ecf20Sopenharmony_ci if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 38628c2ecf20Sopenharmony_ci printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 38638c2ecf20Sopenharmony_ci byte_count, scsicmd->underflow); 38648c2ecf20Sopenharmony_ci } 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci return byte_count; 38678c2ecf20Sopenharmony_ci} 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_cistatic long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci unsigned long byte_count = 0; 38738c2ecf20Sopenharmony_ci u64 addr; 38748c2ecf20Sopenharmony_ci int nseg; 38758c2ecf20Sopenharmony_ci struct scatterlist *sg; 38768c2ecf20Sopenharmony_ci int i; 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci // Get rid of old data 38798c2ecf20Sopenharmony_ci psg->count = 0; 38808c2ecf20Sopenharmony_ci psg->sg[0].addr[0] = 0; 38818c2ecf20Sopenharmony_ci psg->sg[0].addr[1] = 0; 38828c2ecf20Sopenharmony_ci psg->sg[0].count = 0; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci nseg = scsi_dma_map(scsicmd); 38858c2ecf20Sopenharmony_ci if (nseg <= 0) 38868c2ecf20Sopenharmony_ci return nseg; 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci scsi_for_each_sg(scsicmd, sg, nseg, i) { 38898c2ecf20Sopenharmony_ci int count = sg_dma_len(sg); 38908c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 38918c2ecf20Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); 38928c2ecf20Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32(addr>>32); 38938c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(count); 38948c2ecf20Sopenharmony_ci byte_count += count; 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci psg->count = cpu_to_le32(nseg); 38978c2ecf20Sopenharmony_ci /* hba wants the size to be exact */ 38988c2ecf20Sopenharmony_ci if (byte_count > scsi_bufflen(scsicmd)) { 38998c2ecf20Sopenharmony_ci u32 temp = le32_to_cpu(psg->sg[i-1].count) - 39008c2ecf20Sopenharmony_ci (byte_count - scsi_bufflen(scsicmd)); 39018c2ecf20Sopenharmony_ci psg->sg[i-1].count = cpu_to_le32(temp); 39028c2ecf20Sopenharmony_ci byte_count = scsi_bufflen(scsicmd); 39038c2ecf20Sopenharmony_ci } 39048c2ecf20Sopenharmony_ci /* Check for command underflow */ 39058c2ecf20Sopenharmony_ci if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 39068c2ecf20Sopenharmony_ci printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 39078c2ecf20Sopenharmony_ci byte_count, scsicmd->underflow); 39088c2ecf20Sopenharmony_ci } 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci return byte_count; 39118c2ecf20Sopenharmony_ci} 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_cistatic long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg) 39148c2ecf20Sopenharmony_ci{ 39158c2ecf20Sopenharmony_ci unsigned long byte_count = 0; 39168c2ecf20Sopenharmony_ci int nseg; 39178c2ecf20Sopenharmony_ci struct scatterlist *sg; 39188c2ecf20Sopenharmony_ci int i; 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci // Get rid of old data 39218c2ecf20Sopenharmony_ci psg->count = 0; 39228c2ecf20Sopenharmony_ci psg->sg[0].next = 0; 39238c2ecf20Sopenharmony_ci psg->sg[0].prev = 0; 39248c2ecf20Sopenharmony_ci psg->sg[0].addr[0] = 0; 39258c2ecf20Sopenharmony_ci psg->sg[0].addr[1] = 0; 39268c2ecf20Sopenharmony_ci psg->sg[0].count = 0; 39278c2ecf20Sopenharmony_ci psg->sg[0].flags = 0; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci nseg = scsi_dma_map(scsicmd); 39308c2ecf20Sopenharmony_ci if (nseg <= 0) 39318c2ecf20Sopenharmony_ci return nseg; 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci scsi_for_each_sg(scsicmd, sg, nseg, i) { 39348c2ecf20Sopenharmony_ci int count = sg_dma_len(sg); 39358c2ecf20Sopenharmony_ci u64 addr = sg_dma_address(sg); 39368c2ecf20Sopenharmony_ci psg->sg[i].next = 0; 39378c2ecf20Sopenharmony_ci psg->sg[i].prev = 0; 39388c2ecf20Sopenharmony_ci psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); 39398c2ecf20Sopenharmony_ci psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); 39408c2ecf20Sopenharmony_ci psg->sg[i].count = cpu_to_le32(count); 39418c2ecf20Sopenharmony_ci psg->sg[i].flags = 0; 39428c2ecf20Sopenharmony_ci byte_count += count; 39438c2ecf20Sopenharmony_ci } 39448c2ecf20Sopenharmony_ci psg->count = cpu_to_le32(nseg); 39458c2ecf20Sopenharmony_ci /* hba wants the size to be exact */ 39468c2ecf20Sopenharmony_ci if (byte_count > scsi_bufflen(scsicmd)) { 39478c2ecf20Sopenharmony_ci u32 temp = le32_to_cpu(psg->sg[i-1].count) - 39488c2ecf20Sopenharmony_ci (byte_count - scsi_bufflen(scsicmd)); 39498c2ecf20Sopenharmony_ci psg->sg[i-1].count = cpu_to_le32(temp); 39508c2ecf20Sopenharmony_ci byte_count = scsi_bufflen(scsicmd); 39518c2ecf20Sopenharmony_ci } 39528c2ecf20Sopenharmony_ci /* Check for command underflow */ 39538c2ecf20Sopenharmony_ci if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 39548c2ecf20Sopenharmony_ci printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 39558c2ecf20Sopenharmony_ci byte_count, scsicmd->underflow); 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci return byte_count; 39598c2ecf20Sopenharmony_ci} 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_cistatic long aac_build_sgraw2(struct scsi_cmnd *scsicmd, 39628c2ecf20Sopenharmony_ci struct aac_raw_io2 *rio2, int sg_max) 39638c2ecf20Sopenharmony_ci{ 39648c2ecf20Sopenharmony_ci unsigned long byte_count = 0; 39658c2ecf20Sopenharmony_ci int nseg; 39668c2ecf20Sopenharmony_ci struct scatterlist *sg; 39678c2ecf20Sopenharmony_ci int i, conformable = 0; 39688c2ecf20Sopenharmony_ci u32 min_size = PAGE_SIZE, cur_size; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci nseg = scsi_dma_map(scsicmd); 39718c2ecf20Sopenharmony_ci if (nseg <= 0) 39728c2ecf20Sopenharmony_ci return nseg; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci scsi_for_each_sg(scsicmd, sg, nseg, i) { 39758c2ecf20Sopenharmony_ci int count = sg_dma_len(sg); 39768c2ecf20Sopenharmony_ci u64 addr = sg_dma_address(sg); 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci BUG_ON(i >= sg_max); 39798c2ecf20Sopenharmony_ci rio2->sge[i].addrHigh = cpu_to_le32((u32)(addr>>32)); 39808c2ecf20Sopenharmony_ci rio2->sge[i].addrLow = cpu_to_le32((u32)(addr & 0xffffffff)); 39818c2ecf20Sopenharmony_ci cur_size = cpu_to_le32(count); 39828c2ecf20Sopenharmony_ci rio2->sge[i].length = cur_size; 39838c2ecf20Sopenharmony_ci rio2->sge[i].flags = 0; 39848c2ecf20Sopenharmony_ci if (i == 0) { 39858c2ecf20Sopenharmony_ci conformable = 1; 39868c2ecf20Sopenharmony_ci rio2->sgeFirstSize = cur_size; 39878c2ecf20Sopenharmony_ci } else if (i == 1) { 39888c2ecf20Sopenharmony_ci rio2->sgeNominalSize = cur_size; 39898c2ecf20Sopenharmony_ci min_size = cur_size; 39908c2ecf20Sopenharmony_ci } else if ((i+1) < nseg && cur_size != rio2->sgeNominalSize) { 39918c2ecf20Sopenharmony_ci conformable = 0; 39928c2ecf20Sopenharmony_ci if (cur_size < min_size) 39938c2ecf20Sopenharmony_ci min_size = cur_size; 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci byte_count += count; 39968c2ecf20Sopenharmony_ci } 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci /* hba wants the size to be exact */ 39998c2ecf20Sopenharmony_ci if (byte_count > scsi_bufflen(scsicmd)) { 40008c2ecf20Sopenharmony_ci u32 temp = le32_to_cpu(rio2->sge[i-1].length) - 40018c2ecf20Sopenharmony_ci (byte_count - scsi_bufflen(scsicmd)); 40028c2ecf20Sopenharmony_ci rio2->sge[i-1].length = cpu_to_le32(temp); 40038c2ecf20Sopenharmony_ci byte_count = scsi_bufflen(scsicmd); 40048c2ecf20Sopenharmony_ci } 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci rio2->sgeCnt = cpu_to_le32(nseg); 40078c2ecf20Sopenharmony_ci rio2->flags |= cpu_to_le16(RIO2_SG_FORMAT_IEEE1212); 40088c2ecf20Sopenharmony_ci /* not conformable: evaluate required sg elements */ 40098c2ecf20Sopenharmony_ci if (!conformable) { 40108c2ecf20Sopenharmony_ci int j, nseg_new = nseg, err_found; 40118c2ecf20Sopenharmony_ci for (i = min_size / PAGE_SIZE; i >= 1; --i) { 40128c2ecf20Sopenharmony_ci err_found = 0; 40138c2ecf20Sopenharmony_ci nseg_new = 2; 40148c2ecf20Sopenharmony_ci for (j = 1; j < nseg - 1; ++j) { 40158c2ecf20Sopenharmony_ci if (rio2->sge[j].length % (i*PAGE_SIZE)) { 40168c2ecf20Sopenharmony_ci err_found = 1; 40178c2ecf20Sopenharmony_ci break; 40188c2ecf20Sopenharmony_ci } 40198c2ecf20Sopenharmony_ci nseg_new += (rio2->sge[j].length / (i*PAGE_SIZE)); 40208c2ecf20Sopenharmony_ci } 40218c2ecf20Sopenharmony_ci if (!err_found) 40228c2ecf20Sopenharmony_ci break; 40238c2ecf20Sopenharmony_ci } 40248c2ecf20Sopenharmony_ci if (i > 0 && nseg_new <= sg_max) { 40258c2ecf20Sopenharmony_ci int ret = aac_convert_sgraw2(rio2, i, nseg, nseg_new); 40268c2ecf20Sopenharmony_ci 40278c2ecf20Sopenharmony_ci if (ret < 0) 40288c2ecf20Sopenharmony_ci return ret; 40298c2ecf20Sopenharmony_ci } 40308c2ecf20Sopenharmony_ci } else 40318c2ecf20Sopenharmony_ci rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci /* Check for command underflow */ 40348c2ecf20Sopenharmony_ci if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 40358c2ecf20Sopenharmony_ci printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", 40368c2ecf20Sopenharmony_ci byte_count, scsicmd->underflow); 40378c2ecf20Sopenharmony_ci } 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci return byte_count; 40408c2ecf20Sopenharmony_ci} 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_cistatic int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new) 40438c2ecf20Sopenharmony_ci{ 40448c2ecf20Sopenharmony_ci struct sge_ieee1212 *sge; 40458c2ecf20Sopenharmony_ci int i, j, pos; 40468c2ecf20Sopenharmony_ci u32 addr_low; 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci if (aac_convert_sgl == 0) 40498c2ecf20Sopenharmony_ci return 0; 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci sge = kmalloc_array(nseg_new, sizeof(struct sge_ieee1212), GFP_ATOMIC); 40528c2ecf20Sopenharmony_ci if (sge == NULL) 40538c2ecf20Sopenharmony_ci return -ENOMEM; 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci for (i = 1, pos = 1; i < nseg-1; ++i) { 40568c2ecf20Sopenharmony_ci for (j = 0; j < rio2->sge[i].length / (pages * PAGE_SIZE); ++j) { 40578c2ecf20Sopenharmony_ci addr_low = rio2->sge[i].addrLow + j * pages * PAGE_SIZE; 40588c2ecf20Sopenharmony_ci sge[pos].addrLow = addr_low; 40598c2ecf20Sopenharmony_ci sge[pos].addrHigh = rio2->sge[i].addrHigh; 40608c2ecf20Sopenharmony_ci if (addr_low < rio2->sge[i].addrLow) 40618c2ecf20Sopenharmony_ci sge[pos].addrHigh++; 40628c2ecf20Sopenharmony_ci sge[pos].length = pages * PAGE_SIZE; 40638c2ecf20Sopenharmony_ci sge[pos].flags = 0; 40648c2ecf20Sopenharmony_ci pos++; 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci } 40678c2ecf20Sopenharmony_ci sge[pos] = rio2->sge[nseg-1]; 40688c2ecf20Sopenharmony_ci memcpy(&rio2->sge[1], &sge[1], (nseg_new-1)*sizeof(struct sge_ieee1212)); 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci kfree(sge); 40718c2ecf20Sopenharmony_ci rio2->sgeCnt = cpu_to_le32(nseg_new); 40728c2ecf20Sopenharmony_ci rio2->flags |= cpu_to_le16(RIO2_SGL_CONFORMANT); 40738c2ecf20Sopenharmony_ci rio2->sgeNominalSize = pages * PAGE_SIZE; 40748c2ecf20Sopenharmony_ci return 0; 40758c2ecf20Sopenharmony_ci} 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_cistatic long aac_build_sghba(struct scsi_cmnd *scsicmd, 40788c2ecf20Sopenharmony_ci struct aac_hba_cmd_req *hbacmd, 40798c2ecf20Sopenharmony_ci int sg_max, 40808c2ecf20Sopenharmony_ci u64 sg_address) 40818c2ecf20Sopenharmony_ci{ 40828c2ecf20Sopenharmony_ci unsigned long byte_count = 0; 40838c2ecf20Sopenharmony_ci int nseg; 40848c2ecf20Sopenharmony_ci struct scatterlist *sg; 40858c2ecf20Sopenharmony_ci int i; 40868c2ecf20Sopenharmony_ci u32 cur_size; 40878c2ecf20Sopenharmony_ci struct aac_hba_sgl *sge; 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci nseg = scsi_dma_map(scsicmd); 40908c2ecf20Sopenharmony_ci if (nseg <= 0) { 40918c2ecf20Sopenharmony_ci byte_count = nseg; 40928c2ecf20Sopenharmony_ci goto out; 40938c2ecf20Sopenharmony_ci } 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci if (nseg > HBA_MAX_SG_EMBEDDED) 40968c2ecf20Sopenharmony_ci sge = &hbacmd->sge[2]; 40978c2ecf20Sopenharmony_ci else 40988c2ecf20Sopenharmony_ci sge = &hbacmd->sge[0]; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci scsi_for_each_sg(scsicmd, sg, nseg, i) { 41018c2ecf20Sopenharmony_ci int count = sg_dma_len(sg); 41028c2ecf20Sopenharmony_ci u64 addr = sg_dma_address(sg); 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_ci WARN_ON(i >= sg_max); 41058c2ecf20Sopenharmony_ci sge->addr_hi = cpu_to_le32((u32)(addr>>32)); 41068c2ecf20Sopenharmony_ci sge->addr_lo = cpu_to_le32((u32)(addr & 0xffffffff)); 41078c2ecf20Sopenharmony_ci cur_size = cpu_to_le32(count); 41088c2ecf20Sopenharmony_ci sge->len = cur_size; 41098c2ecf20Sopenharmony_ci sge->flags = 0; 41108c2ecf20Sopenharmony_ci byte_count += count; 41118c2ecf20Sopenharmony_ci sge++; 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci sge--; 41158c2ecf20Sopenharmony_ci /* hba wants the size to be exact */ 41168c2ecf20Sopenharmony_ci if (byte_count > scsi_bufflen(scsicmd)) { 41178c2ecf20Sopenharmony_ci u32 temp; 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci temp = le32_to_cpu(sge->len) - byte_count 41208c2ecf20Sopenharmony_ci - scsi_bufflen(scsicmd); 41218c2ecf20Sopenharmony_ci sge->len = cpu_to_le32(temp); 41228c2ecf20Sopenharmony_ci byte_count = scsi_bufflen(scsicmd); 41238c2ecf20Sopenharmony_ci } 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci if (nseg <= HBA_MAX_SG_EMBEDDED) { 41268c2ecf20Sopenharmony_ci hbacmd->emb_data_desc_count = cpu_to_le32(nseg); 41278c2ecf20Sopenharmony_ci sge->flags = cpu_to_le32(0x40000000); 41288c2ecf20Sopenharmony_ci } else { 41298c2ecf20Sopenharmony_ci /* not embedded */ 41308c2ecf20Sopenharmony_ci hbacmd->sge[0].flags = cpu_to_le32(0x80000000); 41318c2ecf20Sopenharmony_ci hbacmd->emb_data_desc_count = (u8)cpu_to_le32(1); 41328c2ecf20Sopenharmony_ci hbacmd->sge[0].addr_hi = (u32)cpu_to_le32(sg_address >> 32); 41338c2ecf20Sopenharmony_ci hbacmd->sge[0].addr_lo = 41348c2ecf20Sopenharmony_ci cpu_to_le32((u32)(sg_address & 0xffffffff)); 41358c2ecf20Sopenharmony_ci } 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci /* Check for command underflow */ 41388c2ecf20Sopenharmony_ci if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { 41398c2ecf20Sopenharmony_ci pr_warn("aacraid: cmd len %08lX cmd underflow %08X\n", 41408c2ecf20Sopenharmony_ci byte_count, scsicmd->underflow); 41418c2ecf20Sopenharmony_ci } 41428c2ecf20Sopenharmony_ciout: 41438c2ecf20Sopenharmony_ci return byte_count; 41448c2ecf20Sopenharmony_ci} 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci#ifdef AAC_DETAILED_STATUS_INFO 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_cistruct aac_srb_status_info { 41498c2ecf20Sopenharmony_ci u32 status; 41508c2ecf20Sopenharmony_ci char *str; 41518c2ecf20Sopenharmony_ci}; 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_cistatic struct aac_srb_status_info srb_status_info[] = { 41558c2ecf20Sopenharmony_ci { SRB_STATUS_PENDING, "Pending Status"}, 41568c2ecf20Sopenharmony_ci { SRB_STATUS_SUCCESS, "Success"}, 41578c2ecf20Sopenharmony_ci { SRB_STATUS_ABORTED, "Aborted Command"}, 41588c2ecf20Sopenharmony_ci { SRB_STATUS_ABORT_FAILED, "Abort Failed"}, 41598c2ecf20Sopenharmony_ci { SRB_STATUS_ERROR, "Error Event"}, 41608c2ecf20Sopenharmony_ci { SRB_STATUS_BUSY, "Device Busy"}, 41618c2ecf20Sopenharmony_ci { SRB_STATUS_INVALID_REQUEST, "Invalid Request"}, 41628c2ecf20Sopenharmony_ci { SRB_STATUS_INVALID_PATH_ID, "Invalid Path ID"}, 41638c2ecf20Sopenharmony_ci { SRB_STATUS_NO_DEVICE, "No Device"}, 41648c2ecf20Sopenharmony_ci { SRB_STATUS_TIMEOUT, "Timeout"}, 41658c2ecf20Sopenharmony_ci { SRB_STATUS_SELECTION_TIMEOUT, "Selection Timeout"}, 41668c2ecf20Sopenharmony_ci { SRB_STATUS_COMMAND_TIMEOUT, "Command Timeout"}, 41678c2ecf20Sopenharmony_ci { SRB_STATUS_MESSAGE_REJECTED, "Message Rejected"}, 41688c2ecf20Sopenharmony_ci { SRB_STATUS_BUS_RESET, "Bus Reset"}, 41698c2ecf20Sopenharmony_ci { SRB_STATUS_PARITY_ERROR, "Parity Error"}, 41708c2ecf20Sopenharmony_ci { SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"}, 41718c2ecf20Sopenharmony_ci { SRB_STATUS_NO_HBA, "No HBA"}, 41728c2ecf20Sopenharmony_ci { SRB_STATUS_DATA_OVERRUN, "Data Overrun/Data Underrun"}, 41738c2ecf20Sopenharmony_ci { SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"}, 41748c2ecf20Sopenharmony_ci { SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"}, 41758c2ecf20Sopenharmony_ci { SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"}, 41768c2ecf20Sopenharmony_ci { SRB_STATUS_REQUEST_FLUSHED, "Request Flushed"}, 41778c2ecf20Sopenharmony_ci { SRB_STATUS_DELAYED_RETRY, "Delayed Retry"}, 41788c2ecf20Sopenharmony_ci { SRB_STATUS_INVALID_LUN, "Invalid LUN"}, 41798c2ecf20Sopenharmony_ci { SRB_STATUS_INVALID_TARGET_ID, "Invalid TARGET ID"}, 41808c2ecf20Sopenharmony_ci { SRB_STATUS_BAD_FUNCTION, "Bad Function"}, 41818c2ecf20Sopenharmony_ci { SRB_STATUS_ERROR_RECOVERY, "Error Recovery"}, 41828c2ecf20Sopenharmony_ci { SRB_STATUS_NOT_STARTED, "Not Started"}, 41838c2ecf20Sopenharmony_ci { SRB_STATUS_NOT_IN_USE, "Not In Use"}, 41848c2ecf20Sopenharmony_ci { SRB_STATUS_FORCE_ABORT, "Force Abort"}, 41858c2ecf20Sopenharmony_ci { SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"}, 41868c2ecf20Sopenharmony_ci { 0xff, "Unknown Error"} 41878c2ecf20Sopenharmony_ci}; 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_cichar *aac_get_status_string(u32 status) 41908c2ecf20Sopenharmony_ci{ 41918c2ecf20Sopenharmony_ci int i; 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(srb_status_info); i++) 41948c2ecf20Sopenharmony_ci if (srb_status_info[i].status == status) 41958c2ecf20Sopenharmony_ci return srb_status_info[i].str; 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci return "Bad Status Code"; 41988c2ecf20Sopenharmony_ci} 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci#endif 4201