diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 22:51:42 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-21 22:51:42 +0300 |
commit | cdc194705d26fdd7fc5446b5d830f2bbe2b22c30 (patch) | |
tree | 91a643f38d490e092855792576a7e903a419cfe1 /drivers/scsi/aacraid | |
parent | 772c8f6f3bbd3ceb94a89373473083e3e1113554 (diff) | |
parent | d1da522fb8a70b8c527d4ad15f9e62218cc00f2c (diff) | |
download | linux-cdc194705d26fdd7fc5446b5d830f2bbe2b22c30.tar.xz |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This update includes the usual round of major driver updates (ncr5380,
ufs, lpfc, be2iscsi, hisi_sas, storvsc, cxlflash, aacraid,
megaraid_sas, ...).
There's also an assortment of minor fixes and the major update of
switching a bunch of drivers to pci_alloc_irq_vectors from Christoph"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (188 commits)
scsi: megaraid_sas: handle dma_addr_t right on 32-bit
scsi: megaraid_sas: array overflow in megasas_dump_frame()
scsi: snic: switch to pci_irq_alloc_vectors
scsi: megaraid_sas: driver version upgrade
scsi: megaraid_sas: Change RAID_1_10_RMW_CMDS to RAID_1_PEER_CMDS and set value to 2
scsi: megaraid_sas: Indentation and smatch warning fixes
scsi: megaraid_sas: Cleanup VD_EXT_DEBUG and SPAN_DEBUG related debug prints
scsi: megaraid_sas: Increase internal command pool
scsi: megaraid_sas: Use synchronize_irq to wait for IRQs to complete
scsi: megaraid_sas: Bail out the driver load if ld_list_query fails
scsi: megaraid_sas: Change build_mpt_mfi_pass_thru to return void
scsi: megaraid_sas: During OCR, if get_ctrl_info fails do not continue with OCR
scsi: megaraid_sas: Do not set fp_possible if TM capable for non-RW syspdIO, change fp_possible to bool
scsi: megaraid_sas: Remove unused pd_index from megasas_build_ld_nonrw_fusion
scsi: megaraid_sas: megasas_return_cmd does not memset IO frame to zero
scsi: megaraid_sas: max_fw_cmds are decremented twice, remove duplicate
scsi: megaraid_sas: update can_queue only if the new value is less
scsi: megaraid_sas: Change max_cmd from u32 to u16 in all functions
scsi: megaraid_sas: set pd_after_lb from MR_BuildRaidContext and initialize pDevHandle to MR_DEVHANDLE_INVALID
scsi: megaraid_sas: latest controller OCR capability from FW before sending shutdown DCMD
...
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 1288 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 644 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commctrl.c | 342 | ||||
-rw-r--r-- | drivers/scsi/aacraid/comminit.c | 330 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 964 | ||||
-rw-r--r-- | drivers/scsi/aacraid/dpcsup.c | 159 | ||||
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 562 | ||||
-rw-r--r-- | drivers/scsi/aacraid/nark.c | 3 | ||||
-rw-r--r-- | drivers/scsi/aacraid/rkt.c | 5 | ||||
-rw-r--r-- | drivers/scsi/aacraid/rx.c | 17 | ||||
-rw-r--r-- | drivers/scsi/aacraid/sa.c | 9 | ||||
-rw-r--r-- | drivers/scsi/aacraid/src.c | 336 |
12 files changed, 3452 insertions, 1207 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 1ee7c654f7b8..907f1e80665b 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +23,11 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * + * Module Name: + * aachba.c + * + * Abstract: Contains Interfaces to manage IOs. + * */ #include <linux/kernel.h> @@ -62,6 +68,7 @@ #define SENCODE_END_OF_DATA 0x00 #define SENCODE_BECOMING_READY 0x04 #define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_UNRECOVERED_READ_ERROR 0x11 #define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A #define SENCODE_INVALID_COMMAND 0x20 #define SENCODE_LBA_OUT_OF_RANGE 0x21 @@ -106,6 +113,8 @@ #define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 #define ASENCODE_OVERLAPPED_COMMAND 0x00 +#define AAC_STAT_GOOD (DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD) + #define BYTE0(x) (unsigned char)(x) #define BYTE1(x) (unsigned char)((x) >> 8) #define BYTE2(x) (unsigned char)((x) >> 16) @@ -164,46 +173,56 @@ struct inquiry_data { }; /* Added for VPD 0x83 */ -typedef struct { - u8 CodeSet:4; /* VPD_CODE_SET */ - u8 Reserved:4; - u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */ - u8 Reserved2:4; - u8 Reserved3; - u8 IdentifierLength; - u8 VendId[8]; - u8 ProductId[16]; - u8 SerialNumber[8]; /* SN in ASCII */ - -} TVPD_ID_Descriptor_Type_1; +struct tvpd_id_descriptor_type_1 { + u8 codeset:4; /* VPD_CODE_SET */ + u8 reserved:4; + u8 identifiertype:4; /* VPD_IDENTIFIER_TYPE */ + u8 reserved2:4; + u8 reserved3; + u8 identifierlength; + u8 venid[8]; + u8 productid[16]; + u8 serialnumber[8]; /* SN in ASCII */ -typedef struct { - u8 CodeSet:4; /* VPD_CODE_SET */ - u8 Reserved:4; - u8 IdentifierType:4; /* VPD_IDENTIFIER_TYPE */ - u8 Reserved2:4; - u8 Reserved3; - u8 IdentifierLength; - struct TEU64Id { +}; + +struct tvpd_id_descriptor_type_2 { + u8 codeset:4; /* VPD_CODE_SET */ + u8 reserved:4; + u8 identifiertype:4; /* VPD_IDENTIFIER_TYPE */ + u8 reserved2:4; + u8 reserved3; + u8 identifierlength; + struct teu64id { u32 Serial; /* The serial number supposed to be 40 bits, * bit we only support 32, so make the last byte zero. */ - u8 Reserved; - u8 VendId[3]; - } EU64Id; + u8 reserved; + u8 venid[3]; + } eu64id; -} TVPD_ID_Descriptor_Type_2; +}; -typedef struct { +struct tvpd_id_descriptor_type_3 { + u8 codeset : 4; /* VPD_CODE_SET */ + u8 reserved : 4; + u8 identifiertype : 4; /* VPD_IDENTIFIER_TYPE */ + u8 reserved2 : 4; + u8 reserved3; + u8 identifierlength; + u8 Identifier[16]; +}; + +struct tvpd_page83 { u8 DeviceType:5; u8 DeviceTypeQualifier:3; u8 PageCode; - u8 Reserved; + u8 reserved; u8 PageLength; - TVPD_ID_Descriptor_Type_1 IdDescriptorType1; - TVPD_ID_Descriptor_Type_2 IdDescriptorType2; - -} TVPD_Page83; + struct tvpd_id_descriptor_type_1 type1; + struct tvpd_id_descriptor_type_2 type2; + struct tvpd_id_descriptor_type_3 type3; +}; /* * M O D U L E G L O B A L S @@ -214,9 +233,13 @@ static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg); static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg); static long aac_build_sgraw2(struct scsi_cmnd *scsicmd, struct aac_raw_io2 *rio2, int sg_max); +static long aac_build_sghba(struct scsi_cmnd *scsicmd, + struct aac_hba_cmd_req *hbacmd, + int sg_max, u64 sg_address); static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new); static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); +static int aac_send_hba_fib(struct scsi_cmnd *scsicmd); #ifdef AAC_DETAILED_STATUS_INFO static char *aac_get_status_string(u32 status); #endif @@ -327,7 +350,7 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd, } scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; device = scsicmd->device; - if (unlikely(!device || !scsi_device_online(device))) { + if (unlikely(!device)) { dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n")); aac_fib_complete(fibptr); return 0; @@ -473,16 +496,26 @@ int aac_get_containers(struct aac_dev *dev) if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) maximum_num_containers = MAXIMUM_NUM_CONTAINERS; - fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers, - GFP_KERNEL); - if (!fsa_dev_ptr) - return -ENOMEM; + if (dev->fsa_dev == NULL || + dev->maximum_num_containers != maximum_num_containers) { + + fsa_dev_ptr = dev->fsa_dev; + + dev->fsa_dev = kcalloc(maximum_num_containers, + sizeof(*fsa_dev_ptr), GFP_KERNEL); + + kfree(fsa_dev_ptr); + fsa_dev_ptr = NULL; - dev->fsa_dev = fsa_dev_ptr; - dev->maximum_num_containers = maximum_num_containers; - for (index = 0; index < dev->maximum_num_containers; ) { - fsa_dev_ptr[index].devname[0] = '\0'; + if (!dev->fsa_dev) + return -ENOMEM; + + dev->maximum_num_containers = maximum_num_containers; + } + for (index = 0; index < dev->maximum_num_containers; index++) { + dev->fsa_dev[index].devname[0] = '\0'; + dev->fsa_dev[index].valid = 0; status = aac_probe_container(dev, index); @@ -490,12 +523,6 @@ int aac_get_containers(struct aac_dev *dev) printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); break; } - - /* - * If there are no more containers, then stop asking. - */ - if (++index >= status) - break; } return status; } @@ -602,6 +629,7 @@ static void _aac_probe_container2(void * context, struct fib * fibptr) struct fsa_dev_info *fsa_dev_ptr; int (*callback)(struct scsi_cmnd *); struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; + int i; if (!aac_valid_context(scsicmd, fibptr)) @@ -624,6 +652,10 @@ static void _aac_probe_container2(void * context, struct fib * fibptr) fsa_dev_ptr->block_size = le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size); } + for (i = 0; i < 16; i++) + fsa_dev_ptr->identifier[i] = + dresp->mnt[0].fileinfo.bdevinfo + .identifier[i]; fsa_dev_ptr->valid = 1; /* sense_key holds the current state of the spin-up */ if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY)) @@ -918,6 +950,28 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex) inqstrcpy ("V1.0", str->prl); } +static void build_vpd83_type3(struct tvpd_page83 *vpdpage83data, + struct aac_dev *dev, struct scsi_cmnd *scsicmd) +{ + int container; + + vpdpage83data->type3.codeset = 1; + vpdpage83data->type3.identifiertype = 3; + vpdpage83data->type3.identifierlength = sizeof(vpdpage83data->type3) + - 4; + + for (container = 0; container < dev->maximum_num_containers; + container++) { + + if (scmd_id(scsicmd) == container) { + memcpy(vpdpage83data->type3.Identifier, + dev->fsa_dev[container].identifier, + 16); + break; + } + } +} + static void get_container_serial_callback(void *context, struct fib * fibptr) { struct aac_get_serial_resp * get_serial_reply; @@ -935,39 +989,47 @@ static void get_container_serial_callback(void *context, struct fib * fibptr) /*Check to see if it's for VPD 0x83 or 0x80 */ if (scsicmd->cmnd[2] == 0x83) { /* vpd page 0x83 - Device Identification Page */ + struct aac_dev *dev; int i; - TVPD_Page83 VPDPage83Data; + struct tvpd_page83 vpdpage83data; + + dev = (struct aac_dev *)scsicmd->device->host->hostdata; - memset(((u8 *)&VPDPage83Data), 0, - sizeof(VPDPage83Data)); + memset(((u8 *)&vpdpage83data), 0, + sizeof(vpdpage83data)); /* DIRECT_ACCESS_DEVIC */ - VPDPage83Data.DeviceType = 0; + vpdpage83data.DeviceType = 0; /* DEVICE_CONNECTED */ - VPDPage83Data.DeviceTypeQualifier = 0; + vpdpage83data.DeviceTypeQualifier = 0; /* VPD_DEVICE_IDENTIFIERS */ - VPDPage83Data.PageCode = 0x83; - VPDPage83Data.Reserved = 0; - VPDPage83Data.PageLength = - sizeof(VPDPage83Data.IdDescriptorType1) + - sizeof(VPDPage83Data.IdDescriptorType2); + vpdpage83data.PageCode = 0x83; + vpdpage83data.reserved = 0; + vpdpage83data.PageLength = + sizeof(vpdpage83data.type1) + + sizeof(vpdpage83data.type2); + + /* VPD 83 Type 3 is not supported for ARC */ + if (dev->sa_firmware) + vpdpage83data.PageLength += + sizeof(vpdpage83data.type3); /* T10 Vendor Identifier Field Format */ - /* VpdCodeSetAscii */ - VPDPage83Data.IdDescriptorType1.CodeSet = 2; + /* VpdcodesetAscii */ + vpdpage83data.type1.codeset = 2; /* VpdIdentifierTypeVendorId */ - VPDPage83Data.IdDescriptorType1.IdentifierType = 1; - VPDPage83Data.IdDescriptorType1.IdentifierLength = - sizeof(VPDPage83Data.IdDescriptorType1) - 4; + vpdpage83data.type1.identifiertype = 1; + vpdpage83data.type1.identifierlength = + sizeof(vpdpage83data.type1) - 4; /* "ADAPTEC " for adaptec */ - memcpy(VPDPage83Data.IdDescriptorType1.VendId, + memcpy(vpdpage83data.type1.venid, "ADAPTEC ", - sizeof(VPDPage83Data.IdDescriptorType1.VendId)); - memcpy(VPDPage83Data.IdDescriptorType1.ProductId, + sizeof(vpdpage83data.type1.venid)); + memcpy(vpdpage83data.type1.productid, "ARRAY ", sizeof( - VPDPage83Data.IdDescriptorType1.ProductId)); + vpdpage83data.type1.productid)); /* Convert to ascii based serial number. * The LSB is the the end. @@ -976,32 +1038,41 @@ static void get_container_serial_callback(void *context, struct fib * fibptr) u8 temp = (u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF); if (temp > 0x9) { - VPDPage83Data.IdDescriptorType1.SerialNumber[i] = + vpdpage83data.type1.serialnumber[i] = 'A' + (temp - 0xA); } else { - VPDPage83Data.IdDescriptorType1.SerialNumber[i] = + vpdpage83data.type1.serialnumber[i] = '0' + temp; } } /* VpdCodeSetBinary */ - VPDPage83Data.IdDescriptorType2.CodeSet = 1; - /* VpdIdentifierTypeEUI64 */ - VPDPage83Data.IdDescriptorType2.IdentifierType = 2; - VPDPage83Data.IdDescriptorType2.IdentifierLength = - sizeof(VPDPage83Data.IdDescriptorType2) - 4; + vpdpage83data.type2.codeset = 1; + /* VpdidentifiertypeEUI64 */ + vpdpage83data.type2.identifiertype = 2; + vpdpage83data.type2.identifierlength = + sizeof(vpdpage83data.type2) - 4; - VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0; - VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0; - VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0; + vpdpage83data.type2.eu64id.venid[0] = 0xD0; + vpdpage83data.type2.eu64id.venid[1] = 0; + vpdpage83data.type2.eu64id.venid[2] = 0; - VPDPage83Data.IdDescriptorType2.EU64Id.Serial = + vpdpage83data.type2.eu64id.Serial = get_serial_reply->uid; - VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0; + vpdpage83data.type2.eu64id.reserved = 0; + + /* + * VpdIdentifierTypeFCPHName + * VPD 0x83 Type 3 not supported for ARC + */ + if (dev->sa_firmware) { + build_vpd83_type3(&vpdpage83data, + dev, scsicmd); + } /* Move the inquiry data to the response buffer. */ - scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data, - sizeof(VPDPage83Data)); + scsi_sg_copy_from_buffer(scsicmd, &vpdpage83data, + sizeof(vpdpage83data)); } else { /* It must be for VPD 0x80 */ char sp[13]; @@ -1144,7 +1215,9 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3 long ret; aac_fib_init(fib); - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) { + if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || + dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && + !dev->sync_mode) { struct aac_raw_io2 *readcmd2; readcmd2 = (struct aac_raw_io2 *) fib_data(fib); memset(readcmd2, 0, sizeof(struct aac_raw_io2)); @@ -1270,7 +1343,9 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u long ret; aac_fib_init(fib); - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) { + if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || + dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) && + !dev->sync_mode) { struct aac_raw_io2 *writecmd2; writecmd2 = (struct aac_raw_io2 *) fib_data(fib); memset(writecmd2, 0, sizeof(struct aac_raw_io2)); @@ -1435,6 +1510,52 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd return srbcmd; } +static struct aac_hba_cmd_req *aac_construct_hbacmd(struct fib *fib, + struct scsi_cmnd *cmd) +{ + struct aac_hba_cmd_req *hbacmd; + struct aac_dev *dev; + int bus, target; + u64 address; + + dev = (struct aac_dev *)cmd->device->host->hostdata; + + hbacmd = (struct aac_hba_cmd_req *)fib->hw_fib_va; + memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ + /* iu_type is a parameter of aac_hba_send */ + switch (cmd->sc_data_direction) { + case DMA_TO_DEVICE: + hbacmd->byte1 = 2; + break; + case DMA_FROM_DEVICE: + case DMA_BIDIRECTIONAL: + hbacmd->byte1 = 1; + break; + case DMA_NONE: + default: + break; + } + hbacmd->lun[1] = cpu_to_le32(cmd->device->lun); + + bus = aac_logical_to_phys(scmd_channel(cmd)); + target = scmd_id(cmd); + hbacmd->it_nexus = dev->hba_map[bus][target].rmw_nexus; + + /* we fill in reply_qid later in aac_src_deliver_message */ + /* we fill in iu_type, request_id later in aac_hba_send */ + /* we fill in emb_data_desc_count later in aac_build_sghba */ + + memcpy(hbacmd->cdb, cmd->cmnd, cmd->cmd_len); + hbacmd->data_length = cpu_to_le32(scsi_bufflen(cmd)); + + address = (u64)fib->hw_error_pa; + hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); + hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); + hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + + return hbacmd; +} + static void aac_srb_callback(void *context, struct fib * fibptr); static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) @@ -1505,11 +1626,243 @@ static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) return aac_scsi_32(fib, cmd); } +static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd) +{ + struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd); + struct aac_dev *dev; + long ret; + + dev = (struct aac_dev *)cmd->device->host->hostdata; + + ret = aac_build_sghba(cmd, hbacmd, + dev->scsi_host_ptr->sg_tablesize, (u64)fib->hw_sgl_pa); + if (ret < 0) + return ret; + + /* + * Now send the HBA command to the adapter + */ + fib->hbacmd_size = 64 + le32_to_cpu(hbacmd->emb_data_desc_count) * + sizeof(struct aac_hba_sgl); + + return aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, fib, + (fib_callback) aac_hba_callback, + (void *) cmd); +} + +int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target) +{ + struct fib *fibptr; + struct aac_srb *srbcmd; + struct sgmap64 *sg64; + struct aac_ciss_identify_pd *identify_resp; + dma_addr_t addr; + u32 vbus, vid; + u16 fibsize, datasize; + int rcode = -ENOMEM; + + + fibptr = aac_fib_alloc(dev); + if (!fibptr) + goto out; + + fibsize = sizeof(struct aac_srb) - + sizeof(struct sgentry) + sizeof(struct sgentry64); + datasize = sizeof(struct aac_ciss_identify_pd); + + identify_resp = pci_alloc_consistent(dev->pdev, datasize, &addr); + + if (!identify_resp) + goto fib_free_ptr; + + vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus); + vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget); + + aac_fib_init(fibptr); + + srbcmd = (struct aac_srb *) fib_data(fibptr); + srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); + srbcmd->channel = cpu_to_le32(vbus); + srbcmd->id = cpu_to_le32(vid); + srbcmd->lun = 0; + srbcmd->flags = cpu_to_le32(SRB_DataIn); + srbcmd->timeout = cpu_to_le32(10); + srbcmd->retry_limit = 0; + srbcmd->cdb_size = cpu_to_le32(12); + srbcmd->count = cpu_to_le32(datasize); + + memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); + srbcmd->cdb[0] = 0x26; + srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF); + srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE; + + sg64 = (struct sgmap64 *)&srbcmd->sg; + sg64->count = cpu_to_le32(1); + sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16)); + sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + sg64->sg[0].count = cpu_to_le32(datasize); + + rcode = aac_fib_send(ScsiPortCommand64, + fibptr, fibsize, FsaNormal, 1, 1, NULL, NULL); + + if (identify_resp->current_queue_depth_limit <= 0 || + identify_resp->current_queue_depth_limit > 32) + dev->hba_map[bus][target].qd_limit = 32; + else + dev->hba_map[bus][target].qd_limit = + identify_resp->current_queue_depth_limit; + + pci_free_consistent(dev->pdev, datasize, (void *)identify_resp, addr); + + aac_fib_complete(fibptr); + +fib_free_ptr: + aac_fib_free(fibptr); +out: + return rcode; +} + +/** + * aac_update hba_map()- update current hba map with data from FW + * @dev: aac_dev structure + * @phys_luns: FW information from report phys luns + * + * Update our hba map with the information gathered from the FW + */ +void aac_update_hba_map(struct aac_dev *dev, + struct aac_ciss_phys_luns_resp *phys_luns, int rescan) +{ + /* ok and extended reporting */ + u32 lun_count, nexus; + u32 i, bus, target; + u8 expose_flag, attribs; + u8 devtype; + + lun_count = ((phys_luns->list_length[0] << 24) + + (phys_luns->list_length[1] << 16) + + (phys_luns->list_length[2] << 8) + + (phys_luns->list_length[3])) / 24; + + for (i = 0; i < lun_count; ++i) { + + bus = phys_luns->lun[i].level2[1] & 0x3f; + target = phys_luns->lun[i].level2[0]; + expose_flag = phys_luns->lun[i].bus >> 6; + attribs = phys_luns->lun[i].node_ident[9]; + nexus = *((u32 *) &phys_luns->lun[i].node_ident[12]); + + if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS) + continue; + + dev->hba_map[bus][target].expose = expose_flag; + + if (expose_flag != 0) { + devtype = AAC_DEVTYPE_RAID_MEMBER; + goto update_devtype; + } + + if (nexus != 0 && (attribs & 8)) { + devtype = AAC_DEVTYPE_NATIVE_RAW; + dev->hba_map[bus][target].rmw_nexus = + nexus; + } else + devtype = AAC_DEVTYPE_ARC_RAW; + + if (devtype != AAC_DEVTYPE_NATIVE_RAW) + goto update_devtype; + + if (aac_issue_bmic_identify(dev, bus, target) < 0) + dev->hba_map[bus][target].qd_limit = 32; + +update_devtype: + if (rescan == AAC_INIT) + dev->hba_map[bus][target].devtype = devtype; + else + dev->hba_map[bus][target].new_devtype = devtype; + } +} + +/** + * aac_report_phys_luns() Process topology change + * @dev: aac_dev structure + * @fibptr: fib pointer + * + * Execute a CISS REPORT PHYS LUNS and process the results into + * the current hba_map. + */ +int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan) +{ + int fibsize, datasize; + struct aac_ciss_phys_luns_resp *phys_luns; + struct aac_srb *srbcmd; + struct sgmap64 *sg64; + dma_addr_t addr; + u32 vbus, vid; + int rcode = 0; + + /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */ + fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + + sizeof(struct sgentry64); + datasize = sizeof(struct aac_ciss_phys_luns_resp) + + (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); + + phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent( + dev->pdev, datasize, &addr); + + if (phys_luns == NULL) { + rcode = -ENOMEM; + goto err_out; + } + + vbus = (u32) le16_to_cpu( + dev->supplement_adapter_info.VirtDeviceBus); + vid = (u32) le16_to_cpu( + dev->supplement_adapter_info.VirtDeviceTarget); + + aac_fib_init(fibptr); + + srbcmd = (struct aac_srb *) fib_data(fibptr); + srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); + srbcmd->channel = cpu_to_le32(vbus); + srbcmd->id = cpu_to_le32(vid); + srbcmd->lun = 0; + srbcmd->flags = cpu_to_le32(SRB_DataIn); + srbcmd->timeout = cpu_to_le32(10); + srbcmd->retry_limit = 0; + srbcmd->cdb_size = cpu_to_le32(12); + srbcmd->count = cpu_to_le32(datasize); + + memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); + srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS; + srbcmd->cdb[1] = 2; /* extended reporting */ + srbcmd->cdb[8] = (u8)(datasize >> 8); + srbcmd->cdb[9] = (u8)(datasize); + + sg64 = (struct sgmap64 *) &srbcmd->sg; + sg64->count = cpu_to_le32(1); + sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr)); + sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr)); + sg64->sg[0].count = cpu_to_le32(datasize); + + rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize, + FsaNormal, 1, 1, NULL, NULL); + + /* analyse data */ + if (rcode >= 0 && phys_luns->resp_flag == 2) { + /* ok and extended reporting */ + aac_update_hba_map(dev, phys_luns, rescan); + } + + pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr); +err_out: + return rcode; +} + int aac_get_adapter_info(struct aac_dev* dev) { struct fib* fibptr; int rcode; - u32 tmp; + u32 tmp, bus, target; struct aac_adapter_info *info; struct aac_bus_info *command; struct aac_bus_info_response *bus_info; @@ -1540,6 +1893,7 @@ int aac_get_adapter_info(struct aac_dev* dev) } memcpy(&dev->adapter_info, info, sizeof(*info)); + dev->supplement_adapter_info.VirtDeviceBus = 0xffff; if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) { struct aac_supplement_adapter_info * sinfo; @@ -1567,6 +1921,13 @@ int aac_get_adapter_info(struct aac_dev* dev) } + /* reset all previous mapped devices (i.e. for init. after IOP_RESET) */ + for (bus = 0; bus < AAC_MAX_BUSES; bus++) { + for (target = 0; target < AAC_MAX_TARGETS; target++) { + dev->hba_map[bus][target].devtype = 0; + dev->hba_map[bus][target].qd_limit = 0; + } + } /* * GetBusInfo @@ -1599,6 +1960,12 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); } + if (!dev->sync_mode && dev->sa_firmware && + dev->supplement_adapter_info.VirtDeviceBus != 0xffff) { + /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */ + rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT); + } + if (!dev->in_reset) { char buffer[16]; tmp = le32_to_cpu(dev->adapter_info.kernelrev); @@ -1765,6 +2132,11 @@ int aac_get_adapter_info(struct aac_dev* dev) (dev->scsi_host_ptr->sg_tablesize * 8) + 112; } } + if (!dev->sync_mode && dev->sa_firmware && + dev->scsi_host_ptr->sg_tablesize > HBA_MAX_SG_SEPARATE) + dev->scsi_host_ptr->sg_tablesize = dev->sg_tablesize = + HBA_MAX_SG_SEPARATE; + /* FIB should be freed only after getting the response from the F/W */ if (rcode != -ERESTARTSYS) { aac_fib_complete(fibptr); @@ -1845,6 +2217,15 @@ static void io_callback(void *context, struct fib * fibptr) min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); break; + case ST_MEDERR: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; + set_sense(&dev->fsa_dev[cid].sense_data, MEDIUM_ERROR, + SENCODE_UNRECOVERED_READ_ERROR, ASENCODE_NO_SENSE, 0, 0); + memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); + break; default: #ifdef AAC_DETAILED_STATUS_INFO printk(KERN_WARNING "io_callback: io failed, status = %d\n", @@ -2312,7 +2693,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd) int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { - u32 cid; + u32 cid, bus; struct Scsi_Host *host = scsicmd->device->host; struct aac_dev *dev = (struct aac_dev *)host->hostdata; struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; @@ -2330,8 +2711,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if((cid >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)) { scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; + goto scsi_done_ret; } /* @@ -2359,15 +2739,30 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) } } } else { /* check for physical non-dasd devices */ - if (dev->nondasd_support || expose_physicals || - dev->jbod) { + bus = aac_logical_to_phys(scmd_channel(scsicmd)); + if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && + (dev->hba_map[bus][cid].expose + == AAC_HIDE_DISK)){ + if (scsicmd->cmnd[0] == INQUIRY) { + scsicmd->result = DID_NO_CONNECT << 16; + goto scsi_done_ret; + } + } + + if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && + dev->hba_map[bus][cid].devtype + == AAC_DEVTYPE_NATIVE_RAW) { + if (dev->in_reset) + return -1; + return aac_send_hba_fib(scsicmd); + } else if (dev->nondasd_support || expose_physicals || + dev->jbod) { if (dev->in_reset) return -1; return aac_send_srb_fib(scsicmd); } else { scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; + goto scsi_done_ret; } } } @@ -2385,13 +2780,34 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; + goto scsi_done_ret; } - - /* Handle commands here that don't really require going out to the adapter */ switch (scsicmd->cmnd[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + if (dev->in_reset) + return -1; + return aac_read(scsicmd); + + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + if (dev->in_reset) + return -1; + return aac_write(scsicmd); + + case SYNCHRONIZE_CACHE: + if (((aac_cache & 6) == 6) && dev->cache_protected) { + scsicmd->result = AAC_STAT_GOOD; + break; + } + /* Issue FIB to tell Firmware to flush it's cache */ + if ((aac_cache & 6) != 2) + return aac_synchronize(scsicmd); case INQUIRY: { struct inquiry_data inq_data; @@ -2414,8 +2830,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[1] = scsicmd->cmnd[2]; scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->result = AAC_STAT_GOOD; } else if (scsicmd->cmnd[2] == 0x80) { /* unit serial number page */ arr[3] = setinqserial(dev, &arr[4], @@ -2426,8 +2841,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (aac_wwn != 2) return aac_get_container_serial( scsicmd); - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->result = AAC_STAT_GOOD; } else if (scsicmd->cmnd[2] == 0x83) { /* vpd page 0x83 - Device Identification Page */ char *sno = (char *)&inq_data; @@ -2436,8 +2850,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (aac_wwn != 2) return aac_get_container_serial( scsicmd); - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->result = AAC_STAT_GOOD; } else { /* vpd page not implemented */ scsicmd->result = DID_OK << 16 | @@ -2452,8 +2865,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); } - scsicmd->scsi_done(scsicmd); - return 0; + break; } inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ @@ -2469,9 +2881,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; } if (dev->in_reset) return -1; @@ -2519,10 +2930,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; } case READ_CAPACITY: @@ -2547,11 +2956,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; } case MODE_SENSE: @@ -2629,10 +3035,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) scsi_sg_copy_from_buffer(scsicmd, (char *)&mpd, mode_buf_length); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; } case MODE_SENSE_10: { @@ -2708,18 +3112,17 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) (char *)&mpd10, mode_buf_length); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; } case REQUEST_SENSE: dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data)); - memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data)); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; + memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + sizeof(struct sense_data)); + memset(&dev->fsa_dev[cid].sense_data, 0, + sizeof(struct sense_data)); + scsicmd->result = AAC_STAT_GOOD; + break; case ALLOW_MEDIUM_REMOVAL: dprintk((KERN_DEBUG "LOCK command.\n")); @@ -2728,9 +3131,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) else fsa_dev_ptr[cid].locked = 0; - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; /* * These commands are all No-Ops */ @@ -2746,80 +3148,41 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; + break; } - /* FALLTHRU */ case RESERVE: case RELEASE: case REZERO_UNIT: case REASSIGN_BLOCKS: case SEEK_10: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; + scsicmd->result = AAC_STAT_GOOD; + break; case START_STOP: return aac_start_stop(scsicmd); - } - - switch (scsicmd->cmnd[0]) - { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - if (dev->in_reset) - return -1; - /* - * Hack to keep track of ordinal number of the device that - * corresponds to a container. Needed to convert - * containers to /dev/sd device names - */ - - if (scsicmd->request->rq_disk) - strlcpy(fsa_dev_ptr[cid].devname, - scsicmd->request->rq_disk->disk_name, - min(sizeof(fsa_dev_ptr[cid].devname), - sizeof(scsicmd->request->rq_disk->disk_name) + 1)); - - return aac_read(scsicmd); - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - if (dev->in_reset) - return -1; - return aac_write(scsicmd); - - case SYNCHRONIZE_CACHE: - if (((aac_cache & 6) == 6) && dev->cache_protected) { - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - } - /* Issue FIB to tell Firmware to flush it's cache */ - if ((aac_cache & 6) != 2) - return aac_synchronize(scsicmd); - /* FALLTHRU */ - default: - /* - * Unhandled commands - */ - dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0])); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, + /* FALLTHRU */ + default: + /* + * Unhandled commands + */ + dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", + scsicmd->cmnd[0])); + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | + SAM_STAT_CHECK_CONDITION; + set_sense(&dev->fsa_dev[cid].sense_data, ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, + memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; } + +scsi_done_ret: + + scsicmd->scsi_done(scsicmd); + return 0; } static int query_disk(struct aac_dev *dev, void __user *arg) @@ -2954,16 +3317,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr) return; BUG_ON(fibptr == NULL); - dev = fibptr->dev; - scsi_dma_unmap(scsicmd); - - /* expose physical device if expose_physicald flag is on */ - if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) - && expose_physicals > 0) - aac_expose_phy_device(scsicmd); + dev = fibptr->dev; srbreply = (struct aac_srb_reply *) fib_data(fibptr); + scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { @@ -2976,158 +3334,176 @@ static void aac_srb_callback(void *context, struct fib * fibptr) */ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) - le32_to_cpu(srbreply->data_xfer_length)); - /* - * First check the fib status - */ + } - if (le32_to_cpu(srbreply->status) != ST_OK) { - int len; - printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8 - | SAM_STAT_CHECK_CONDITION; - memcpy(scsicmd->sense_buffer, - srbreply->sense_data, len); - } + scsi_dma_unmap(scsicmd); - /* - * Next check the srb status - */ - switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { - case SRB_STATUS_ERROR_RECOVERY: - case SRB_STATUS_PENDING: - case SRB_STATUS_SUCCESS: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_DATA_OVERRUN: - switch (scsicmd->cmnd[0]) { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - if (le32_to_cpu(srbreply->data_xfer_length) - < scsicmd->underflow) - printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); - else - printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; - case INQUIRY: { - scsicmd->result = DID_OK << 16 - | COMMAND_COMPLETE << 8; - break; - } - default: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - } - break; - case SRB_STATUS_ABORTED: - scsicmd->result = DID_ABORT << 16 | ABORT << 8; - break; - case SRB_STATUS_ABORT_FAILED: - /* - * Not sure about this one - but assuming the - * hba was trying to abort for some reason - */ - scsicmd->result = DID_ERROR << 16 | ABORT << 8; + /* expose physical device if expose_physicald flag is on */ + if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) + && expose_physicals > 0) + aac_expose_phy_device(scsicmd); + + /* + * First check the fib status + */ + + if (le32_to_cpu(srbreply->status) != ST_OK) { + int len; + + pr_warn("aac_srb_callback: srb failed, status = %d\n", + le32_to_cpu(srbreply->status)); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8 + | SAM_STAT_CHECK_CONDITION; + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } + + /* + * Next check the srb status + */ + switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { + case SRB_STATUS_ERROR_RECOVERY: + case SRB_STATUS_PENDING: + case SRB_STATUS_SUCCESS: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case SRB_STATUS_DATA_OVERRUN: + switch (scsicmd->cmnd[0]) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + case READ_16: + case WRITE_16: + if (le32_to_cpu(srbreply->data_xfer_length) + < scsicmd->underflow) + pr_warn("aacraid: SCSI CMD underflow\n"); + else + pr_warn("aacraid: SCSI CMD Data Overrun\n"); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; break; - case SRB_STATUS_PARITY_ERROR: - scsicmd->result = DID_PARITY << 16 - | MSG_PARITY_ERROR << 8; + case INQUIRY: + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; break; - case SRB_STATUS_NO_DEVICE: - case SRB_STATUS_INVALID_PATH_ID: - case SRB_STATUS_INVALID_TARGET_ID: - case SRB_STATUS_INVALID_LUN: - case SRB_STATUS_SELECTION_TIMEOUT: - scsicmd->result = DID_NO_CONNECT << 16 - | COMMAND_COMPLETE << 8; + default: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; break; + } + break; + case SRB_STATUS_ABORTED: + scsicmd->result = DID_ABORT << 16 | ABORT << 8; + break; + case SRB_STATUS_ABORT_FAILED: + /* + * Not sure about this one - but assuming the + * hba was trying to abort for some reason + */ + scsicmd->result = DID_ERROR << 16 | ABORT << 8; + break; + case SRB_STATUS_PARITY_ERROR: + scsicmd->result = DID_PARITY << 16 + | MSG_PARITY_ERROR << 8; + break; + case SRB_STATUS_NO_DEVICE: + case SRB_STATUS_INVALID_PATH_ID: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_SELECTION_TIMEOUT: + scsicmd->result = DID_NO_CONNECT << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_COMMAND_TIMEOUT: - case SRB_STATUS_TIMEOUT: - scsicmd->result = DID_TIME_OUT << 16 - | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_TIMEOUT: + scsicmd->result = DID_TIME_OUT << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUSY: - scsicmd->result = DID_BUS_BUSY << 16 - | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUSY: + scsicmd->result = DID_BUS_BUSY << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUS_RESET: - scsicmd->result = DID_RESET << 16 - | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUS_RESET: + scsicmd->result = DID_RESET << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_MESSAGE_REJECTED: - scsicmd->result = DID_ERROR << 16 - | MESSAGE_REJECT << 8; - break; - case SRB_STATUS_REQUEST_FLUSHED: - case SRB_STATUS_ERROR: - case SRB_STATUS_INVALID_REQUEST: - case SRB_STATUS_REQUEST_SENSE_FAILED: - case SRB_STATUS_NO_HBA: - case SRB_STATUS_UNEXPECTED_BUS_FREE: - case SRB_STATUS_PHASE_SEQUENCE_FAILURE: - case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: - case SRB_STATUS_DELAYED_RETRY: - case SRB_STATUS_BAD_FUNCTION: - case SRB_STATUS_NOT_STARTED: - case SRB_STATUS_NOT_IN_USE: - case SRB_STATUS_FORCE_ABORT: - case SRB_STATUS_DOMAIN_VALIDATION_FAIL: - default: + case SRB_STATUS_MESSAGE_REJECTED: + scsicmd->result = DID_ERROR << 16 + | MESSAGE_REJECT << 8; + break; + case SRB_STATUS_REQUEST_FLUSHED: + case SRB_STATUS_ERROR: + case SRB_STATUS_INVALID_REQUEST: + case SRB_STATUS_REQUEST_SENSE_FAILED: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_UNEXPECTED_BUS_FREE: + case SRB_STATUS_PHASE_SEQUENCE_FAILURE: + case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: + case SRB_STATUS_DELAYED_RETRY: + case SRB_STATUS_BAD_FUNCTION: + case SRB_STATUS_NOT_STARTED: + case SRB_STATUS_NOT_IN_USE: + case SRB_STATUS_FORCE_ABORT: + case SRB_STATUS_DOMAIN_VALIDATION_FAIL: + default: #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", - le32_to_cpu(srbreply->srb_status) & 0x3F, - aac_get_status_string( - le32_to_cpu(srbreply->srb_status) & 0x3F), - scsicmd->cmnd[0], - le32_to_cpu(srbreply->scsi_status)); + pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n", + le32_to_cpu(srbreply->srb_status) & 0x3F, + aac_get_status_string( + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], + le32_to_cpu(srbreply->scsi_status)); #endif - if ((scsicmd->cmnd[0] == ATA_12) - || (scsicmd->cmnd[0] == ATA_16)) { - if (scsicmd->cmnd[2] & (0x01 << 5)) { - scsicmd->result = DID_OK << 16 - | COMMAND_COMPLETE << 8; - break; - } else { - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; - } + /* + * When the CC bit is SET by the host in ATA pass thru CDB, + * driver is supposed to return DID_OK + * + * When the CC bit is RESET by the host, driver should + * return DID_ERROR + */ + if ((scsicmd->cmnd[0] == ATA_12) + || (scsicmd->cmnd[0] == ATA_16)) { + + if (scsicmd->cmnd[2] & (0x01 << 5)) { + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; + break; } else { scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; - break; + break; } + } else { + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; + break; } - if (le32_to_cpu(srbreply->scsi_status) - == SAM_STAT_CHECK_CONDITION) { - int len; + } + if (le32_to_cpu(srbreply->scsi_status) + == SAM_STAT_CHECK_CONDITION) { + int len; - scsicmd->result |= SAM_STAT_CHECK_CONDITION; - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); + scsicmd->result |= SAM_STAT_CHECK_CONDITION; + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", - le32_to_cpu(srbreply->status), len); + pr_warn("aac_srb_callback: check condition, status = %d len=%d\n", + le32_to_cpu(srbreply->status), len); #endif - memcpy(scsicmd->sense_buffer, - srbreply->sense_data, len); - } + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); } + /* * OR in the scsi status (already shifted up a bit) */ @@ -3137,9 +3513,152 @@ static void aac_srb_callback(void *context, struct fib * fibptr) scsicmd->scsi_done(scsicmd); } +static void hba_resp_task_complete(struct aac_dev *dev, + struct scsi_cmnd *scsicmd, + struct aac_hba_resp *err) { + + scsicmd->result = err->status; + /* set residual count */ + scsi_set_resid(scsicmd, le32_to_cpu(err->residual_count)); + + switch (err->status) { + case SAM_STAT_GOOD: + scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case SAM_STAT_CHECK_CONDITION: + { + int len; + + len = min_t(u8, err->sense_response_data_len, + SCSI_SENSE_BUFFERSIZE); + if (len) + memcpy(scsicmd->sense_buffer, + err->sense_response_buf, len); + scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + } + case SAM_STAT_BUSY: + scsicmd->result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; + break; + case SAM_STAT_TASK_ABORTED: + scsicmd->result |= DID_ABORT << 16 | ABORT << 8; + break; + case SAM_STAT_RESERVATION_CONFLICT: + case SAM_STAT_TASK_SET_FULL: + default: + scsicmd->result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8; + break; + } +} + +static void hba_resp_task_failure(struct aac_dev *dev, + struct scsi_cmnd *scsicmd, + struct aac_hba_resp *err) +{ + switch (err->status) { + case HBA_RESP_STAT_HBAMODE_DISABLED: + { + u32 bus, cid; + + bus = aac_logical_to_phys(scmd_channel(scsicmd)); + cid = scmd_id(scsicmd); + if (dev->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { + dev->hba_map[bus][cid].devtype = AAC_DEVTYPE_ARC_RAW; + dev->hba_map[bus][cid].rmw_nexus = 0xffffffff; + } + scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + break; + } + case HBA_RESP_STAT_IO_ERROR: + case HBA_RESP_STAT_NO_PATH_TO_DEVICE: + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8 | SAM_STAT_BUSY; + break; + case HBA_RESP_STAT_IO_ABORTED: + scsicmd->result = DID_ABORT << 16 | ABORT << 8; + break; + case HBA_RESP_STAT_INVALID_DEVICE: + scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + break; + case HBA_RESP_STAT_UNDERRUN: + /* UNDERRUN is OK */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case HBA_RESP_STAT_OVERRUN: + default: + scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; + break; + } +} + +/** + * + * aac_hba_callback + * @context: the context set in the fib - here it is scsi cmd + * @fibptr: pointer to the fib + * + * Handles the completion of a native HBA scsi command + * + */ +void aac_hba_callback(void *context, struct fib *fibptr) +{ + struct aac_dev *dev; + struct scsi_cmnd *scsicmd; + + struct aac_hba_resp *err = + &((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err; + + scsicmd = (struct scsi_cmnd *) context; + + if (!aac_valid_context(scsicmd, fibptr)) + return; + + WARN_ON(fibptr == NULL); + dev = fibptr->dev; + + if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF)) + scsi_dma_unmap(scsicmd); + + if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { + /* fast response */ + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + goto out; + } + + switch (err->service_response) { + case HBA_RESP_SVCRES_TASK_COMPLETE: + hba_resp_task_complete(dev, scsicmd, err); + break; + case HBA_RESP_SVCRES_FAILURE: + hba_resp_task_failure(dev, scsicmd, err); + break; + case HBA_RESP_SVCRES_TMF_REJECTED: + scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; + break; + case HBA_RESP_SVCRES_TMF_LUN_INVALID: + scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + break; + case HBA_RESP_SVCRES_TMF_COMPLETE: + case HBA_RESP_SVCRES_TMF_SUCCEEDED: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + default: + scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; + break; + } + +out: + aac_fib_complete(fibptr); + + if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) + scsicmd->SCp.sent_command = 1; + else + scsicmd->scsi_done(scsicmd); +} + /** * - * aac_send_scb_fib + * aac_send_srb_fib * @scsicmd: the scsi command block * * This routine will form a FIB and fill in the aac_srb from the @@ -3182,6 +3701,54 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) return -1; } +/** + * + * aac_send_hba_fib + * @scsicmd: the scsi command block + * + * This routine will form a FIB and fill in the aac_hba_cmd_req from the + * scsicmd passed in. + */ +static int aac_send_hba_fib(struct scsi_cmnd *scsicmd) +{ + struct fib *cmd_fibcontext; + struct aac_dev *dev; + int status; + + dev = shost_priv(scsicmd->device->host); + if (scmd_id(scsicmd) >= dev->maximum_num_physicals || + scsicmd->device->lun > AAC_MAX_LUN - 1) { + scsicmd->result = DID_NO_CONNECT << 16; + scsicmd->scsi_done(scsicmd); + return 0; + } + + /* + * Allocate and initialize a Fib then setup a BlockWrite command + */ + cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd); + if (!cmd_fibcontext) + return -1; + + status = aac_adapter_hba(cmd_fibcontext, scsicmd); + + /* + * Check that the command queued to the controller + */ + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; + return 0; + } + + pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n", + status); + aac_fib_complete(cmd_fibcontext); + aac_fib_free(cmd_fibcontext); + + return -1; +} + + static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg) { struct aac_dev *dev; @@ -3434,6 +4001,75 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int return 0; } +static long aac_build_sghba(struct scsi_cmnd *scsicmd, + struct aac_hba_cmd_req *hbacmd, + int sg_max, + u64 sg_address) +{ + unsigned long byte_count = 0; + int nseg; + struct scatterlist *sg; + int i; + u32 cur_size; + struct aac_hba_sgl *sge; + + nseg = scsi_dma_map(scsicmd); + if (nseg <= 0) { + byte_count = nseg; + goto out; + } + + if (nseg > HBA_MAX_SG_EMBEDDED) + sge = &hbacmd->sge[2]; + else + sge = &hbacmd->sge[0]; + + scsi_for_each_sg(scsicmd, sg, nseg, i) { + int count = sg_dma_len(sg); + u64 addr = sg_dma_address(sg); + + WARN_ON(i >= sg_max); + sge->addr_hi = cpu_to_le32((u32)(addr>>32)); + sge->addr_lo = cpu_to_le32((u32)(addr & 0xffffffff)); + cur_size = cpu_to_le32(count); + sge->len = cur_size; + sge->flags = 0; + byte_count += count; + sge++; + } + + sge--; + /* hba wants the size to be exact */ + if (byte_count > scsi_bufflen(scsicmd)) { + u32 temp; + + temp = le32_to_cpu(sge->len) - byte_count + - scsi_bufflen(scsicmd); + sge->len = cpu_to_le32(temp); + byte_count = scsi_bufflen(scsicmd); + } + + if (nseg <= HBA_MAX_SG_EMBEDDED) { + hbacmd->emb_data_desc_count = cpu_to_le32(nseg); + sge->flags = cpu_to_le32(0x40000000); + } else { + /* not embedded */ + hbacmd->sge[0].flags = cpu_to_le32(0x80000000); + hbacmd->emb_data_desc_count = (u8)cpu_to_le32(1); + hbacmd->sge[0].addr_hi = (u32)cpu_to_le32(sg_address >> 32); + hbacmd->sge[0].addr_lo = + cpu_to_le32((u32)(sg_address & 0xffffffff)); + } + + /* Check for command underflow */ + if (scsicmd->underflow && (byte_count < scsicmd->underflow)) { + pr_warn("aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); + } +out: + return byte_count; +} + #ifdef AAC_DETAILED_STATUS_INFO struct aac_srb_status_info { diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index f059c14efa0c..f2344971e3cb 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1,3 +1,37 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aacraid.h + * + * Abstract: Contains all routines for control of the aacraid driver + * + */ + +#ifndef _AACRAID_H_ +#define _AACRAID_H_ #ifndef dprintk # define dprintk(x) #endif @@ -63,8 +97,8 @@ enum { #define PMC_GLOBAL_INT_BIT0 0x00000001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 41066 -# define AAC_DRIVER_BRANCH "-ms" +# define AAC_DRIVER_BUILD 50740 +# define AAC_DRIVER_BRANCH "-custom" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -72,13 +106,311 @@ enum { #define AAC_NUM_IO_FIB (1024 - AAC_NUM_MGT_FIB) #define AAC_NUM_FIB (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB) -#define AAC_MAX_LUN (8) +#define AAC_MAX_LUN 256 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff) #define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256) #define AAC_DEBUG_INSTRUMENT_AIF_DELETE +#define AAC_MAX_NATIVE_TARGETS 1024 +/* Thor: 5 phys. buses: #0: empty, 1-4: 256 targets each */ +#define AAC_MAX_BUSES 5 +#define AAC_MAX_TARGETS 256 +#define AAC_MAX_NATIVE_SIZE 2048 +#define FW_ERROR_BUFFER_SIZE 512 + +/* Thor AIF events */ +#define SA_AIF_HOTPLUG (1<<1) +#define SA_AIF_HARDWARE (1<<2) +#define SA_AIF_PDEV_CHANGE (1<<4) +#define SA_AIF_LDEV_CHANGE (1<<5) +#define SA_AIF_BPSTAT_CHANGE (1<<30) +#define SA_AIF_BPCFG_CHANGE (1<<31) + +#define HBA_MAX_SG_EMBEDDED 28 +#define HBA_MAX_SG_SEPARATE 90 +#define HBA_SENSE_DATA_LEN_MAX 32 +#define HBA_REQUEST_TAG_ERROR_FLAG 0x00000002 +#define HBA_SGL_FLAGS_EXT 0x80000000UL + +struct aac_hba_sgl { + u32 addr_lo; /* Lower 32-bits of SGL element address */ + u32 addr_hi; /* Upper 32-bits of SGL element address */ + u32 len; /* Length of SGL element in bytes */ + u32 flags; /* SGL element flags */ +}; + +enum { + HBA_IU_TYPE_SCSI_CMD_REQ = 0x40, + HBA_IU_TYPE_SCSI_TM_REQ = 0x41, + HBA_IU_TYPE_SATA_REQ = 0x42, + HBA_IU_TYPE_RESP = 0x60, + HBA_IU_TYPE_COALESCED_RESP = 0x61, + HBA_IU_TYPE_INT_COALESCING_CFG_REQ = 0x70 +}; + +enum { + HBA_CMD_BYTE1_DATA_DIR_IN = 0x1, + HBA_CMD_BYTE1_DATA_DIR_OUT = 0x2, + HBA_CMD_BYTE1_DATA_TYPE_DDR = 0x4, + HBA_CMD_BYTE1_CRYPTO_ENABLE = 0x8 +}; + +enum { + HBA_CMD_BYTE1_BITOFF_DATA_DIR_IN = 0x0, + HBA_CMD_BYTE1_BITOFF_DATA_DIR_OUT, + HBA_CMD_BYTE1_BITOFF_DATA_TYPE_DDR, + HBA_CMD_BYTE1_BITOFF_CRYPTO_ENABLE +}; + +enum { + HBA_RESP_DATAPRES_NO_DATA = 0x0, + HBA_RESP_DATAPRES_RESPONSE_DATA, + HBA_RESP_DATAPRES_SENSE_DATA +}; + +enum { + HBA_RESP_SVCRES_TASK_COMPLETE = 0x0, + HBA_RESP_SVCRES_FAILURE, + HBA_RESP_SVCRES_TMF_COMPLETE, + HBA_RESP_SVCRES_TMF_SUCCEEDED, + HBA_RESP_SVCRES_TMF_REJECTED, + HBA_RESP_SVCRES_TMF_LUN_INVALID +}; + +enum { + HBA_RESP_STAT_IO_ERROR = 0x1, + HBA_RESP_STAT_IO_ABORTED, + HBA_RESP_STAT_NO_PATH_TO_DEVICE, + HBA_RESP_STAT_INVALID_DEVICE, + HBA_RESP_STAT_HBAMODE_DISABLED = 0xE, + HBA_RESP_STAT_UNDERRUN = 0x51, + HBA_RESP_STAT_OVERRUN = 0x75 +}; + +struct aac_hba_cmd_req { + u8 iu_type; /* HBA information unit type */ + /* + * byte1: + * [1:0] DIR - 0=No data, 0x1 = IN, 0x2 = OUT + * [2] TYPE - 0=PCI, 1=DDR + * [3] CRYPTO_ENABLE - 0=Crypto disabled, 1=Crypto enabled + */ + u8 byte1; + u8 reply_qid; /* Host reply queue to post response to */ + u8 reserved1; + __le32 it_nexus; /* Device handle for the request */ + __le32 request_id; /* Sender context */ + /* Lower 32-bits of tweak value for crypto enabled IOs */ + __le32 tweak_value_lo; + u8 cdb[16]; /* SCSI CDB of the command */ + u8 lun[8]; /* SCSI LUN of the command */ + + /* Total data length in bytes to be read/written (if any) */ + __le32 data_length; + + /* [2:0] Task Attribute, [6:3] Command Priority */ + u8 attr_prio; + + /* Number of SGL elements embedded in the HBA req */ + u8 emb_data_desc_count; + + __le16 dek_index; /* DEK index for crypto enabled IOs */ + + /* Lower 32-bits of reserved error data target location on the host */ + __le32 error_ptr_lo; + + /* Upper 32-bits of reserved error data target location on the host */ + __le32 error_ptr_hi; + + /* Length of reserved error data area on the host in bytes */ + __le32 error_length; + + /* Upper 32-bits of tweak value for crypto enabled IOs */ + __le32 tweak_value_hi; + + struct aac_hba_sgl sge[HBA_MAX_SG_SEPARATE+2]; /* SG list space */ + + /* + * structure must not exceed + * AAC_MAX_NATIVE_SIZE-FW_ERROR_BUFFER_SIZE + */ +}; + +/* Task Management Functions (TMF) */ +#define HBA_TMF_ABORT_TASK 0x01 +#define HBA_TMF_LUN_RESET 0x08 + +struct aac_hba_tm_req { + u8 iu_type; /* HBA information unit type */ + u8 reply_qid; /* Host reply queue to post response to */ + u8 tmf; /* Task management function */ + u8 reserved1; + + __le32 it_nexus; /* Device handle for the command */ + + u8 lun[8]; /* SCSI LUN */ + + /* Used to hold sender context. */ + __le32 request_id; /* Sender context */ + __le32 reserved2; + + /* Request identifier of managed task */ + __le32 managed_request_id; /* Sender context being managed */ + __le32 reserved3; + + /* Lower 32-bits of reserved error data target location on the host */ + __le32 error_ptr_lo; + /* Upper 32-bits of reserved error data target location on the host */ + __le32 error_ptr_hi; + /* Length of reserved error data area on the host in bytes */ + __le32 error_length; +}; + +struct aac_hba_reset_req { + u8 iu_type; /* HBA information unit type */ + /* 0 - reset specified device, 1 - reset all devices */ + u8 reset_type; + u8 reply_qid; /* Host reply queue to post response to */ + u8 reserved1; + + __le32 it_nexus; /* Device handle for the command */ + __le32 request_id; /* Sender context */ + /* Lower 32-bits of reserved error data target location on the host */ + __le32 error_ptr_lo; + /* Upper 32-bits of reserved error data target location on the host */ + __le32 error_ptr_hi; + /* Length of reserved error data area on the host in bytes */ + __le32 error_length; +}; + +struct aac_hba_resp { + u8 iu_type; /* HBA information unit type */ + u8 reserved1[3]; + __le32 request_identifier; /* sender context */ + __le32 reserved2; + u8 service_response; /* SCSI service response */ + u8 status; /* SCSI status */ + u8 datapres; /* [1:0] - data present, [7:2] - reserved */ + u8 sense_response_data_len; /* Sense/response data length */ + __le32 residual_count; /* Residual data length in bytes */ + /* Sense/response data */ + u8 sense_response_buf[HBA_SENSE_DATA_LEN_MAX]; +}; + +struct aac_native_hba { + union { + struct aac_hba_cmd_req cmd; + struct aac_hba_tm_req tmr; + u8 cmd_bytes[AAC_MAX_NATIVE_SIZE-FW_ERROR_BUFFER_SIZE]; + } cmd; + union { + struct aac_hba_resp err; + u8 resp_bytes[FW_ERROR_BUFFER_SIZE]; + } resp; +}; + +#define CISS_REPORT_PHYSICAL_LUNS 0xc3 +#define WRITE_HOST_WELLNESS 0xa5 +#define CISS_IDENTIFY_PHYSICAL_DEVICE 0x15 +#define BMIC_IN 0x26 +#define BMIC_OUT 0x27 + +struct aac_ciss_phys_luns_resp { + u8 list_length[4]; /* LUN list length (N-7, big endian) */ + u8 resp_flag; /* extended response_flag */ + u8 reserved[3]; + struct _ciss_lun { + u8 tid[3]; /* Target ID */ + u8 bus; /* Bus, flag (bits 6,7) */ + u8 level3[2]; + u8 level2[2]; + u8 node_ident[16]; /* phys. node identifier */ + } lun[1]; /* List of phys. devices */ +}; + +/* + * Interrupts + */ +#define AAC_MAX_HRRQ 64 + +struct aac_ciss_identify_pd { + u8 scsi_bus; /* SCSI Bus number on controller */ + u8 scsi_id; /* SCSI ID on this bus */ + u16 block_size; /* sector size in bytes */ + u32 total_blocks; /* number for sectors on drive */ + u32 reserved_blocks; /* controller reserved (RIS) */ + u8 model[40]; /* Physical Drive Model */ + u8 serial_number[40]; /* Drive Serial Number */ + u8 firmware_revision[8]; /* drive firmware revision */ + u8 scsi_inquiry_bits; /* inquiry byte 7 bits */ + u8 compaq_drive_stamp; /* 0 means drive not stamped */ + u8 last_failure_reason; + + u8 flags; + u8 more_flags; + u8 scsi_lun; /* SCSI LUN for phys drive */ + u8 yet_more_flags; + u8 even_more_flags; + u32 spi_speed_rules; /* SPI Speed :Ultra disable diagnose */ + u8 phys_connector[2]; /* connector number on controller */ + u8 phys_box_on_bus; /* phys enclosure this drive resides */ + u8 phys_bay_in_box; /* phys drv bay this drive resides */ + u32 rpm; /* Drive rotational speed in rpm */ + u8 device_type; /* type of drive */ + u8 sata_version; /* only valid when drive_type is SATA */ + u64 big_total_block_count; + u64 ris_starting_lba; + u32 ris_size; + u8 wwid[20]; + u8 controller_phy_map[32]; + u16 phy_count; + u8 phy_connected_dev_type[256]; + u8 phy_to_drive_bay_num[256]; + u16 phy_to_attached_dev_index[256]; + u8 box_index; + u8 spitfire_support; + u16 extra_physical_drive_flags; + u8 negotiated_link_rate[256]; + u8 phy_to_phy_map[256]; + u8 redundant_path_present_map; + u8 redundant_path_failure_map; + u8 active_path_number; + u16 alternate_paths_phys_connector[8]; + u8 alternate_paths_phys_box_on_port[8]; + u8 multi_lun_device_lun_count; + u8 minimum_good_fw_revision[8]; + u8 unique_inquiry_bytes[20]; + u8 current_temperature_degreesC; + u8 temperature_threshold_degreesC; + u8 max_temperature_degreesC; + u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512 * 2^exp */ + u16 current_queue_depth_limit; + u8 switch_name[10]; + u16 switch_port; + u8 alternate_paths_switch_name[40]; + u8 alternate_paths_switch_port[8]; + u16 power_on_hours; /* valid only if gas gauge supported */ + u16 percent_endurance_used; /* valid only if gas gauge supported. */ + u8 drive_authentication; + u8 smart_carrier_authentication; + u8 smart_carrier_app_fw_version; + u8 smart_carrier_bootloader_fw_version; + u8 SanitizeSecureEraseSupport; + u8 DriveKeyFlags; + u8 encryption_key_name[64]; + u32 misc_drive_flags; + u16 dek_index; + u16 drive_encryption_flags; + u8 sanitize_maximum_time[6]; + u8 connector_info_mode; + u8 connector_info_number[4]; + u8 long_connector_name[64]; + u8 device_unique_identifier[16]; + u8 padto_2K[17]; +} __packed; + /* * These macros convert from physical channels to virtual channels */ @@ -86,6 +418,7 @@ enum { #define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL) #define CONTAINER_TO_ID(cont) (cont) #define CONTAINER_TO_LUN(cont) (0) +#define ENCLOSURE_CHANNEL (3) #define PMC_DEVICE_S6 0x28b #define PMC_DEVICE_S7 0x28c @@ -351,10 +684,10 @@ enum aac_queue_types { /* transport FIB header (PMC) */ struct aac_fib_xporthdr { - u64 HostAddress; /* FIB host address w/o xport header */ - u32 Size; /* FIB size excluding xport header */ - u32 Handle; /* driver handle to reference the FIB */ - u64 Reserved[2]; + __le64 HostAddress; /* FIB host address w/o xport header */ + __le32 Size; /* FIB size excluding xport header */ + __le32 Handle; /* driver handle to reference the FIB */ + __le64 Reserved[2]; }; #define ALIGN32 32 @@ -379,7 +712,7 @@ struct aac_fibhdr { __le32 SenderFibAddressHigh;/* upper 32bit of phys. FIB address */ __le32 TimeStamp; /* otherwise timestamp for FW internal use */ } u; - u32 Handle; /* FIB handle used for MSGU commnunication */ + __le32 Handle; /* FIB handle used for MSGU commnunication */ u32 Previous; /* FW internal use */ u32 Next; /* FW internal use */ }; @@ -489,41 +822,64 @@ enum fib_xfer_state { #define ADAPTER_INIT_STRUCT_REVISION_4 4 // rocket science #define ADAPTER_INIT_STRUCT_REVISION_6 6 /* PMC src */ #define ADAPTER_INIT_STRUCT_REVISION_7 7 /* Denali */ +#define ADAPTER_INIT_STRUCT_REVISION_8 8 // Thor -struct aac_init +union aac_init { - __le32 InitStructRevision; - __le32 Sa_MSIXVectors; - __le32 fsrev; - __le32 CommHeaderAddress; - __le32 FastIoCommAreaAddress; - __le32 AdapterFibsPhysicalAddress; - __le32 AdapterFibsVirtualAddress; - __le32 AdapterFibsSize; - __le32 AdapterFibAlign; - __le32 printfbuf; - __le32 printfbufsiz; - __le32 HostPhysMemPages; /* number of 4k pages of host - physical memory */ - __le32 HostElapsedSeconds; /* number of seconds since 1970. */ - /* - * ADAPTER_INIT_STRUCT_REVISION_4 begins here - */ - __le32 InitFlags; /* flags for supported features */ + struct _r7 { + __le32 init_struct_revision; + __le32 no_of_msix_vectors; + __le32 fsrev; + __le32 comm_header_address; + __le32 fast_io_comm_area_address; + __le32 adapter_fibs_physical_address; + __le32 adapter_fibs_virtual_address; + __le32 adapter_fibs_size; + __le32 adapter_fib_align; + __le32 printfbuf; + __le32 printfbufsiz; + /* number of 4k pages of host phys. mem. */ + __le32 host_phys_mem_pages; + /* number of seconds since 1970. */ + __le32 host_elapsed_seconds; + /* ADAPTER_INIT_STRUCT_REVISION_4 begins here */ + __le32 init_flags; /* flags for supported features */ #define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001 #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010 #define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020 #define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED 0x00000040 #define INITFLAGS_FAST_JBOD_SUPPORTED 0x00000080 #define INITFLAGS_NEW_COMM_TYPE2_SUPPORTED 0x00000100 - __le32 MaxIoCommands; /* max outstanding commands */ - __le32 MaxIoSize; /* largest I/O command */ - __le32 MaxFibSize; /* largest FIB to adapter */ - /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */ - __le32 MaxNumAif; /* max number of aif */ - /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */ - __le32 HostRRQ_AddrLow; - __le32 HostRRQ_AddrHigh; /* Host RRQ (response queue) for SRC */ +#define INITFLAGS_DRIVER_SUPPORTS_HBA_MODE 0x00000400 + __le32 max_io_commands; /* max outstanding commands */ + __le32 max_io_size; /* largest I/O command */ + __le32 max_fib_size; /* largest FIB to adapter */ + /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */ + __le32 max_num_aif; /* max number of aif */ + /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */ + /* Host RRQ (response queue) for SRC */ + __le32 host_rrq_addr_low; + __le32 host_rrq_addr_high; + } r7; + struct _r8 { + /* ADAPTER_INIT_STRUCT_REVISION_8 */ + __le32 init_struct_revision; + __le32 rr_queue_count; + __le32 host_elapsed_seconds; /* number of secs since 1970. */ + __le32 init_flags; + __le32 max_io_size; /* largest I/O command */ + __le32 max_num_aif; /* max number of aif */ + __le32 reserved1; + __le32 reserved2; + struct _rrq { + __le32 host_addr_low; + __le32 host_addr_high; + __le16 msix_id; + __le16 element_count; + __le16 comp_thresh; + __le16 unused; + } rrq[1]; /* up to 64 RRQ addresses */ + } r8; }; enum aac_log_level { @@ -554,7 +910,7 @@ struct adapter_ops void (*adapter_enable_int)(struct aac_dev *dev); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); - int (*adapter_restart)(struct aac_dev *dev, int bled); + int (*adapter_restart)(struct aac_dev *dev, int bled, u8 reset_type); void (*adapter_start)(struct aac_dev *dev); /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); @@ -727,6 +1083,7 @@ struct sa_registers { #define SA_INIT_NUM_MSIXVECTORS 1 +#define SA_MINIPORT_REVISION SA_INIT_NUM_MSIXVECTORS #define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) #define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) @@ -820,32 +1177,37 @@ struct rkt_registers { #define src_inbound rx_inbound struct src_mu_registers { - /* PCI*| Name */ - __le32 reserved0[6]; /* 00h | Reserved */ - __le32 IOAR[2]; /* 18h | IOA->host interrupt register */ - __le32 IDR; /* 20h | Inbound Doorbell Register */ - __le32 IISR; /* 24h | Inbound Int. Status Register */ - __le32 reserved1[3]; /* 28h | Reserved */ - __le32 OIMR; /* 34h | Outbound Int. Mask Register */ - __le32 reserved2[25]; /* 38h | Reserved */ - __le32 ODR_R; /* 9ch | Outbound Doorbell Read */ - __le32 ODR_C; /* a0h | Outbound Doorbell Clear */ - __le32 reserved3[6]; /* a4h | Reserved */ - __le32 OMR; /* bch | Outbound Message Register */ + /* PCI*| Name */ + __le32 reserved0[6]; /* 00h | Reserved */ + __le32 IOAR[2]; /* 18h | IOA->host interrupt register */ + __le32 IDR; /* 20h | Inbound Doorbell Register */ + __le32 IISR; /* 24h | Inbound Int. Status Register */ + __le32 reserved1[3]; /* 28h | Reserved */ + __le32 OIMR; /* 34h | Outbound Int. Mask Register */ + __le32 reserved2[25]; /* 38h | Reserved */ + __le32 ODR_R; /* 9ch | Outbound Doorbell Read */ + __le32 ODR_C; /* a0h | Outbound Doorbell Clear */ + __le32 reserved3[3]; /* a4h | Reserved */ + __le32 SCR0; /* b0h | Scratchpad 0 */ + __le32 reserved4[2]; /* b4h | Reserved */ + __le32 OMR; /* bch | Outbound Message Register */ __le32 IQ_L; /* c0h | Inbound Queue (Low address) */ __le32 IQ_H; /* c4h | Inbound Queue (High address) */ __le32 ODR_MSI; /* c8h | MSI register for sync./AIF */ + __le32 reserved5; /* cch | Reserved */ + __le32 IQN_L; /* d0h | Inbound (native cmd) low */ + __le32 IQN_H; /* d4h | Inbound (native cmd) high */ }; struct src_registers { struct src_mu_registers MUnit; /* 00h - cbh */ union { struct { - __le32 reserved1[130789]; /* cch - 7fc5fh */ + __le32 reserved1[130786]; /* d8h - 7fc5fh */ struct src_inbound IndexRegs; /* 7fc60h */ } tupelo; struct { - __le32 reserved1[973]; /* cch - fffh */ + __le32 reserved1[970]; /* d8h - fffh */ struct src_inbound IndexRegs; /* 1000h */ } denali; } u; @@ -930,6 +1292,7 @@ struct fsa_dev_info { char devname[8]; struct sense_data sense_data; u32 block_size; + u8 identifier[16]; }; struct fib { @@ -958,8 +1321,30 @@ struct fib { struct list_head fiblink; void *data; u32 vector_no; - struct hw_fib *hw_fib_va; /* Actual shared object */ - dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ + struct hw_fib *hw_fib_va; /* also used for native */ + dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ + dma_addr_t hw_sgl_pa; /* extra sgl for native */ + dma_addr_t hw_error_pa; /* error buffer for native */ + u32 hbacmd_size; /* cmd size for native */ +}; + +#define AAC_INIT 0 +#define AAC_RESCAN 1 + +#define AAC_DEVTYPE_RAID_MEMBER 1 +#define AAC_DEVTYPE_ARC_RAW 2 +#define AAC_DEVTYPE_NATIVE_RAW 3 +#define AAC_EXPOSE_DISK 0 +#define AAC_HIDE_DISK 3 + +struct aac_hba_map_info { + __le32 rmw_nexus; /* nexus for native HBA devices */ + u8 devtype; /* device type */ + u8 new_devtype; + u8 reset_state; /* 0 - no reset, 1..x - */ + /* after xth TM LUN reset */ + u16 qd_limit; + u8 expose; /*checks if to expose or not*/ }; /* @@ -1025,7 +1410,28 @@ struct aac_supplement_adapter_info /* StructExpansion == 1 */ __le32 FeatureBits3; __le32 SupportedPerformanceModes; - __le32 ReservedForFutureGrowth[80]; + u8 HostBusType; /* uses HOST_BUS_TYPE_xxx defines */ + u8 HostBusWidth; /* actual width in bits or links */ + u16 HostBusSpeed; /* actual bus speed/link rate in MHz */ + u8 MaxRRCDrives; /* max. number of ITP-RRC drives/pool */ + u8 MaxDiskXtasks; /* max. possible num of DiskX Tasks */ + + u8 CpldVerLoaded; + u8 CpldVerInFlash; + + __le64 MaxRRCCapacity; + __le32 CompiledMaxHistLogLevel; + u8 CustomBoardName[12]; + u16 SupportedCntlrMode; /* identify supported controller mode */ + u16 ReservedForFuture16; + __le32 SupportedOptions3; /* reserved for future options */ + + __le16 VirtDeviceBus; /* virt. SCSI device for Thor */ + __le16 VirtDeviceTarget; + __le16 VirtDeviceLUN; + __le16 Unused; + __le32 ReservedForFutureGrowth[68]; + }; #define AAC_FEATURE_FALCON cpu_to_le32(0x00000010) #define AAC_FEATURE_JBOD cpu_to_le32(0x08000000) @@ -1099,11 +1505,21 @@ struct aac_bus_info_response { #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) #define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) #define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18) +#define AAC_OPT_EXTENDED cpu_to_le32(1<<23) +#define AAC_OPT_NATIVE_HBA cpu_to_le32(1<<25) #define AAC_OPT_NEW_COMM_TYPE1 cpu_to_le32(1<<28) #define AAC_OPT_NEW_COMM_TYPE2 cpu_to_le32(1<<29) #define AAC_OPT_NEW_COMM_TYPE3 cpu_to_le32(1<<30) #define AAC_OPT_NEW_COMM_TYPE4 cpu_to_le32(1<<31) +#define AAC_COMM_PRODUCER 0 +#define AAC_COMM_MESSAGE 1 +#define AAC_COMM_MESSAGE_TYPE1 3 +#define AAC_COMM_MESSAGE_TYPE2 4 +#define AAC_COMM_MESSAGE_TYPE3 5 + +#define AAC_EXTOPT_SA_FIRMWARE cpu_to_le32(1<<1) + /* MSIX context */ struct aac_msix_ctx { int vector_no; @@ -1119,15 +1535,17 @@ struct aac_dev /* * negotiated FIB settings */ - unsigned max_fib_size; - unsigned sg_tablesize; - unsigned max_num_aif; + unsigned int max_fib_size; + unsigned int sg_tablesize; + unsigned int max_num_aif; + + unsigned int max_cmd_size; /* max_fib_size or MAX_NATIVE */ /* * Map for 128 fib objects (64k) */ - dma_addr_t hw_fib_pa; - struct hw_fib *hw_fib_va; + dma_addr_t hw_fib_pa; /* also used for native cmd */ + struct hw_fib *hw_fib_va; /* also used for native cmd */ struct hw_fib *aif_base_va; /* * Fib Headers @@ -1157,21 +1575,23 @@ struct aac_dev resource_size_t base_size, dbg_size; /* Size of * mapped in region */ - - struct aac_init *init; /* Holds initialization info to communicate with adapter */ + /* + * Holds initialization info + * to communicate with adapter + */ + union aac_init *init; dma_addr_t init_pa; /* Holds physical address of the init struct */ - - u32 *host_rrq; /* response queue - * if AAC_COMM_MESSAGE_TYPE1 */ - + /* response queue (if AAC_COMM_MESSAGE_TYPE1) */ + __le32 *host_rrq; dma_addr_t host_rrq_pa; /* phys. address */ /* index into rrq buffer */ u32 host_rrq_idx[AAC_MAX_MSIX]; atomic_t rrq_outstanding[AAC_MAX_MSIX]; u32 fibs_pushed_no; struct pci_dev *pdev; /* Our PCI interface */ - void * printfbuf; /* pointer to buffer used for printf's from the adapter */ - void * comm_addr; /* Base address of Comm area */ + /* pointer to buffer used for printf's from the adapter */ + void *printfbuf; + void *comm_addr; /* Base address of Comm area */ dma_addr_t comm_phys; /* Physical Address of Comm area */ size_t comm_size; @@ -1227,15 +1647,12 @@ struct aac_dev u8 needs_dac; u8 raid_scsi_mode; u8 comm_interface; -# define AAC_COMM_PRODUCER 0 -# define AAC_COMM_MESSAGE 1 -# define AAC_COMM_MESSAGE_TYPE1 3 -# define AAC_COMM_MESSAGE_TYPE2 4 u8 raw_io_interface; u8 raw_io_64; u8 printf_enabled; u8 in_reset; u8 msi; + u8 sa_firmware; int management_fib_count; spinlock_t manage_lock; spinlock_t sync_lock; @@ -1246,7 +1663,10 @@ struct aac_dev u32 max_msix; /* max. MSI-X vectors */ u32 vector_cap; /* MSI-X vector capab.*/ int msi_enabled; /* MSI/MSI-X enabled */ + atomic_t msix_counter; + struct msix_entry msixentry[AAC_MAX_MSIX]; struct aac_msix_ctx aac_msix[AAC_MAX_MSIX]; /* context */ + struct aac_hba_map_info hba_map[AAC_MAX_BUSES][AAC_MAX_TARGETS]; u8 adapter_shutdown; u32 handle_pci_error; }; @@ -1269,8 +1689,8 @@ struct aac_dev #define aac_adapter_check_health(dev) \ (dev)->a_ops.adapter_check_health(dev) -#define aac_adapter_restart(dev,bled) \ - (dev)->a_ops.adapter_restart(dev,bled) +#define aac_adapter_restart(dev, bled, reset_type) \ + ((dev)->a_ops.adapter_restart(dev, bled, reset_type)) #define aac_adapter_start(dev) \ ((dev)->a_ops.adapter_start(dev)) @@ -1300,6 +1720,8 @@ struct aac_dev #define FIB_CONTEXT_FLAG (0x00000002) #define FIB_CONTEXT_FLAG_WAIT (0x00000004) #define FIB_CONTEXT_FLAG_FASTRESP (0x00000008) +#define FIB_CONTEXT_FLAG_NATIVE_HBA (0x00000010) +#define FIB_CONTEXT_FLAG_NATIVE_HBA_TMF (0x00000020) /* * Define the command values @@ -1358,6 +1780,7 @@ struct aac_dev #define ST_IO 5 #define ST_NXIO 6 #define ST_E2BIG 7 +#define ST_MEDERR 8 #define ST_ACCES 13 #define ST_EXIST 17 #define ST_XDEV 18 @@ -1715,6 +2138,8 @@ struct aac_fsinfo { struct aac_blockdevinfo { __le32 block_size; + __le32 logical_phys_map; + u8 identifier[16]; }; union aac_contentinfo { @@ -1940,6 +2365,15 @@ struct revision #define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) #define FSACTL_GET_CONTAINERS 2131 #define FSACTL_SEND_LARGE_FIB CTL_CODE(2138, METHOD_BUFFERED) +#define FSACTL_RESET_IOP CTL_CODE(2140, METHOD_BUFFERED) +#define FSACTL_GET_HBA_INFO CTL_CODE(2150, METHOD_BUFFERED) +/* flags defined for IOP & HW SOFT RESET */ +#define HW_IOP_RESET 0x01 +#define HW_SOFT_RESET 0x02 +#define IOP_HWSOFT_RESET (HW_IOP_RESET | HW_SOFT_RESET) +/* HW Soft Reset register offset */ +#define IBW_SWR_OFFSET 0x4000 +#define SOFT_RESET_TIME 60 struct aac_common @@ -1958,6 +2392,8 @@ struct aac_common #ifdef DBG u32 FibsSent; u32 FibRecved; + u32 NativeSent; + u32 NativeRecved; u32 NoResponseSent; u32 NoResponseRecved; u32 AsyncSent; @@ -1969,6 +2405,56 @@ struct aac_common extern struct aac_common aac_config; +/* + * This is for management ioctl purpose only. + */ +struct aac_hba_info { + + u8 driver_name[50]; + u8 adapter_number; + u8 system_io_bus_number; + u8 device_number; + u32 function_number; + u32 vendor_id; + u32 device_id; + u32 sub_vendor_id; + u32 sub_system_id; + u32 mapped_base_address_size; + u32 base_physical_address_high_part; + u32 base_physical_address_low_part; + + u32 max_command_size; + u32 max_fib_size; + u32 max_scatter_gather_from_os; + u32 max_scatter_gather_to_fw; + u32 max_outstanding_fibs; + + u32 queue_start_threshold; + u32 queue_dump_threshold; + u32 max_io_size_queued; + u32 outstanding_io; + + u32 firmware_build_number; + u32 bios_build_number; + u32 driver_build_number; + u32 serial_number_high_part; + u32 serial_number_low_part; + u32 supported_options; + u32 feature_bits; + u32 currentnumber_ports; + + u8 new_comm_interface:1; + u8 new_commands_supported:1; + u8 disable_passthrough:1; + u8 expose_non_dasd:1; + u8 queue_allowed:1; + u8 bled_check_enabled:1; + u8 reserved1:1; + u8 reserted2:1; + + u32 reserved3[10]; + +}; /* * The following macro is used when sending and receiving FIBs. It is @@ -2096,9 +2582,10 @@ extern struct aac_common aac_config; /* PMC NEW COMM: Request the event data */ #define AifReqEvent 200 +#define AifRawDeviceRemove 203 /* RAW device deleted */ +#define AifNativeDeviceAdd 204 /* native HBA device added */ +#define AifNativeDeviceRemove 205 /* native HBA device removed */ -/* RAW device deleted */ -#define AifRawDeviceRemove 203 /* * Adapter Initiated FIB command structures. Start with the adapter @@ -2131,6 +2618,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) int aac_acquire_irq(struct aac_dev *dev); void aac_free_irq(struct aac_dev *dev); +int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan); +int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target); const char *aac_driverinfo(struct Scsi_Host *); void aac_fib_vector_assign(struct aac_dev *dev); struct fib *aac_fib_alloc(struct aac_dev *dev); @@ -2141,9 +2630,12 @@ void aac_fib_free(struct fib * context); void aac_fib_init(struct fib * context); void aac_printf(struct aac_dev *dev, u32 val); int aac_fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt); +int aac_hba_send(u8 command, struct fib *context, + fib_callback callback, void *ctxt); int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); int aac_fib_complete(struct fib * context); +void aac_hba_callback(void *context, struct fib *fibptr); #define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data) struct aac_dev *aac_init_adapter(struct aac_dev *dev); void aac_src_access_devreg(struct aac_dev *dev, int mode); @@ -2169,7 +2661,7 @@ unsigned int aac_command_normal(struct aac_queue * q); unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, int isAif, int isFastResponse, struct hw_fib *aif_fib); -int aac_reset_adapter(struct aac_dev * dev, int forced); +int aac_reset_adapter(struct aac_dev *dev, int forced, u8 reset_type); int aac_check_health(struct aac_dev * dev); int aac_command_thread(void *data); int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); @@ -2183,7 +2675,6 @@ int aac_rx_select_comm(struct aac_dev *dev, int comm); int aac_rx_deliver_producer(struct fib * fib); char * get_container_type(unsigned type); extern int numacb; -extern int acbsize; extern char aac_driver_version[]; extern int startup_timeout; extern int aif_timeout; @@ -2194,3 +2685,4 @@ extern int aac_commit; extern int update_interval; extern int check_interval; extern int aac_check_reset; +#endif diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index e1daff230c7d..614842a9eb07 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -477,20 +478,24 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) struct fib* srbfib; int status; struct aac_srb *srbcmd = NULL; + struct aac_hba_cmd_req *hbacmd = NULL; struct user_aac_srb *user_srbcmd = NULL; struct user_aac_srb __user *user_srb = arg; struct aac_srb_reply __user *user_reply; - struct aac_srb_reply* reply; + u32 chn; u32 fibsize = 0; u32 flags = 0; s32 rcode = 0; u32 data_dir; - void __user *sg_user[32]; - void *sg_list[32]; + void __user *sg_user[HBA_MAX_SG_EMBEDDED]; + void *sg_list[HBA_MAX_SG_EMBEDDED]; + u32 sg_count[HBA_MAX_SG_EMBEDDED]; u32 sg_indx = 0; u32 byte_count = 0; u32 actual_fibsize64, actual_fibsize = 0; int i; + int is_native_device; + u64 address; if (dev->in_reset) { @@ -507,11 +512,6 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) if (!(srbfib = aac_fib_alloc(dev))) { return -ENOMEM; } - aac_fib_init(srbfib); - /* raw_srb FIB is not FastResponseCapable */ - srbfib->hw_fib_va->header.XferState &= ~cpu_to_le32(FastResponseCapable); - - srbcmd = (struct aac_srb*) fib_data(srbfib); memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ @@ -538,21 +538,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } - user_reply = arg+fibsize; - flags = user_srbcmd->flags; /* from user in cpu order */ - // Fix up srb for endian and force some values - - srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this - srbcmd->channel = cpu_to_le32(user_srbcmd->channel); - srbcmd->id = cpu_to_le32(user_srbcmd->id); - srbcmd->lun = cpu_to_le32(user_srbcmd->lun); - srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); - srbcmd->flags = cpu_to_le32(flags); - srbcmd->retry_limit = 0; // Obsolete parameter - srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); - memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); - switch (flags & (SRB_DataIn | SRB_DataOut)) { case SRB_DataOut: data_dir = DMA_TO_DEVICE; @@ -568,7 +554,12 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) } if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", - le32_to_cpu(srbcmd->sg.count))); + user_srbcmd->sg.count)); + rcode = -EINVAL; + goto cleanup; + } + if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { + dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n")); rcode = -EINVAL; goto cleanup; } @@ -588,13 +579,136 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { - dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); - rcode = -EINVAL; - goto cleanup; + + chn = aac_logical_to_phys(user_srbcmd->channel); + if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS && + dev->hba_map[chn][user_srbcmd->id].devtype == + AAC_DEVTYPE_NATIVE_RAW) { + is_native_device = 1; + hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va; + memset(hbacmd, 0, 96); /* sizeof(*hbacmd) is not necessary */ + + /* iu_type is a parameter of aac_hba_send */ + switch (data_dir) { + case DMA_TO_DEVICE: + hbacmd->byte1 = 2; + break; + case DMA_FROM_DEVICE: + case DMA_BIDIRECTIONAL: + hbacmd->byte1 = 1; + break; + case DMA_NONE: + default: + break; + } + hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun); + hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus; + + /* + * we fill in reply_qid later in aac_src_deliver_message + * we fill in iu_type, request_id later in aac_hba_send + * we fill in emb_data_desc_count, data_length later + * in sg list build + */ + + memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb)); + + address = (u64)srbfib->hw_error_pa; + hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); + hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); + hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + hbacmd->emb_data_desc_count = + cpu_to_le32(user_srbcmd->sg.count); + srbfib->hbacmd_size = 64 + + user_srbcmd->sg.count * sizeof(struct aac_hba_sgl); + + } else { + is_native_device = 0; + aac_fib_init(srbfib); + + /* raw_srb FIB is not FastResponseCapable */ + srbfib->hw_fib_va->header.XferState &= + ~cpu_to_le32(FastResponseCapable); + + srbcmd = (struct aac_srb *) fib_data(srbfib); + + // Fix up srb for endian and force some values + + srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this + srbcmd->channel = cpu_to_le32(user_srbcmd->channel); + srbcmd->id = cpu_to_le32(user_srbcmd->id); + srbcmd->lun = cpu_to_le32(user_srbcmd->lun); + srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); + srbcmd->flags = cpu_to_le32(flags); + srbcmd->retry_limit = 0; // Obsolete parameter + srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); + memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); } + byte_count = 0; - if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { + if (is_native_device) { + struct user_sgmap *usg32 = &user_srbcmd->sg; + struct user_sgmap64 *usg64 = + (struct user_sgmap64 *)&user_srbcmd->sg; + + for (i = 0; i < usg32->count; i++) { + void *p; + u64 addr; + + sg_count[i] = (actual_fibsize64 == fibsize) ? + usg64->sg[i].count : usg32->sg[i].count; + if (sg_count[i] > + (dev->scsi_host_ptr->max_sectors << 9)) { + pr_err("aacraid: upsg->sg[%d].count=%u>%u\n", + i, sg_count[i], + dev->scsi_host_ptr->max_sectors << 9); + rcode = -EINVAL; + goto cleanup; + } + + p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA); + if (!p) { + rcode = -ENOMEM; + goto cleanup; + } + + if (actual_fibsize64 == fibsize) { + addr = (u64)usg64->sg[i].addr[0]; + addr += ((u64)usg64->sg[i].addr[1]) << 32; + } else { + addr = (u64)usg32->sg[i].addr; + } + + sg_user[i] = (void __user *)(uintptr_t)addr; + sg_list[i] = p; // save so we can clean up later + sg_indx = i; + + if (flags & SRB_DataOut) { + if (copy_from_user(p, sg_user[i], + sg_count[i])) { + rcode = -EFAULT; + goto cleanup; + } + } + addr = pci_map_single(dev->pdev, p, sg_count[i], + data_dir); + hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32)); + hbacmd->sge[i].addr_lo = cpu_to_le32( + (u32)(addr & 0xffffffff)); + hbacmd->sge[i].len = cpu_to_le32(sg_count[i]); + hbacmd->sge[i].flags = 0; + byte_count += sg_count[i]; + } + + if (usg32->count > 0) /* embedded sglist */ + hbacmd->sge[usg32->count-1].flags = + cpu_to_le32(0x40000000); + hbacmd->data_length = cpu_to_le32(byte_count); + + status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib, + NULL, NULL); + + } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; @@ -606,7 +720,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) for (i = 0; i < upsg->count; i++) { u64 addr; void* p; - if (upsg->sg[i].count > + + sg_count[i] = upsg->sg[i].count; + if (sg_count[i] > ((dev->adapter_info.options & AAC_OPT_NEW_COMM) ? (dev->scsi_host_ptr->max_sectors << 9) : @@ -615,10 +731,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } /* Does this really need to be GFP_DMA? */ - p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); + p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA); if(!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count,i,upsg->count)); + sg_count[i], i, upsg->count)); rcode = -ENOMEM; goto cleanup; } @@ -629,18 +745,20 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_indx = i; if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ + if (copy_from_user(p, sg_user[i], + sg_count[i])){ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; goto cleanup; } } - addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir); + addr = pci_map_single(dev->pdev, p, + sg_count[i], data_dir); psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); + byte_count += sg_count[i]; + psg->sg[i].count = cpu_to_le32(sg_count[i]); } } else { struct user_sgmap* usg; @@ -657,7 +775,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) for (i = 0; i < usg->count; i++) { u64 addr; void* p; - if (usg->sg[i].count > + + sg_count[i] = usg->sg[i].count; + if (sg_count[i] > ((dev->adapter_info.options & AAC_OPT_NEW_COMM) ? (dev->scsi_host_ptr->max_sectors << 9) : @@ -667,10 +787,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); + p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA); if(!p) { dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); + sg_count[i], i, usg->count)); kfree(usg); rcode = -ENOMEM; goto cleanup; @@ -680,19 +800,21 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_indx = i; if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ + if (copy_from_user(p, sg_user[i], + sg_count[i])) { kfree (usg); dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; goto cleanup; } } - addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); + addr = pci_map_single(dev->pdev, p, + sg_count[i], data_dir); psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); + byte_count += sg_count[i]; + psg->sg[i].count = cpu_to_le32(sg_count[i]); } kfree (usg); } @@ -711,7 +833,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) for (i = 0; i < upsg->count; i++) { uintptr_t addr; void* p; - if (usg->sg[i].count > + + sg_count[i] = usg->sg[i].count; + if (sg_count[i] > ((dev->adapter_info.options & AAC_OPT_NEW_COMM) ? (dev->scsi_host_ptr->max_sectors << 9) : @@ -720,10 +844,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(!p) { + p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA); + if (!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); + sg_count[i], i, usg->count)); rcode = -ENOMEM; goto cleanup; } @@ -734,7 +858,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_indx = i; if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ + if (copy_from_user(p, sg_user[i], + sg_count[i])){ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; goto cleanup; @@ -744,13 +869,15 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); + psg->sg[i].count = cpu_to_le32(sg_count[i]); } } else { for (i = 0; i < upsg->count; i++) { dma_addr_t addr; void* p; - if (upsg->sg[i].count > + + sg_count[i] = upsg->sg[i].count; + if (sg_count[i] > ((dev->adapter_info.options & AAC_OPT_NEW_COMM) ? (dev->scsi_host_ptr->max_sectors << 9) : @@ -758,10 +885,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) rcode = -EINVAL; goto cleanup; } - p = kmalloc(upsg->sg[i].count, GFP_KERNEL); + p = kmalloc(sg_count[i], GFP_KERNEL); if (!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count, i, upsg->count)); + sg_count[i], i, upsg->count)); rcode = -ENOMEM; goto cleanup; } @@ -770,19 +897,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_indx = i; if (flags & SRB_DataOut) { - if(copy_from_user(p, sg_user[i], - upsg->sg[i].count)) { + if (copy_from_user(p, sg_user[i], + sg_count[i])) { dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; goto cleanup; } } addr = pci_map_single(dev->pdev, p, - upsg->sg[i].count, data_dir); + sg_count[i], data_dir); psg->sg[i].addr = cpu_to_le32(addr); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); + byte_count += sg_count[i]; + psg->sg[i].count = cpu_to_le32(sg_count[i]); } } srbcmd->count = cpu_to_le32(byte_count); @@ -792,12 +919,13 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) psg->count = 0; status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); } + if (status == -ERESTARTSYS) { rcode = -ERESTARTSYS; goto cleanup; } - if (status != 0){ + if (status != 0) { dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); rcode = -ENXIO; goto cleanup; @@ -805,11 +933,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) if (flags & SRB_DataIn) { for(i = 0 ; i <= sg_indx; i++){ - byte_count = le32_to_cpu( - (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) - ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count - : srbcmd->sg.sg[i].count); - if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ + if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) { dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); rcode = -EFAULT; goto cleanup; @@ -818,19 +942,50 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) } } - reply = (struct aac_srb_reply *) fib_data(srbfib); - if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){ - dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); - rcode = -EFAULT; - goto cleanup; + user_reply = arg + fibsize; + if (is_native_device) { + struct aac_hba_resp *err = + &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err; + struct aac_srb_reply reply; + + reply.status = ST_OK; + if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) { + /* fast response */ + reply.srb_status = SRB_STATUS_SUCCESS; + reply.scsi_status = 0; + reply.data_xfer_length = byte_count; + } else { + reply.srb_status = err->service_response; + reply.scsi_status = err->status; + reply.data_xfer_length = byte_count - + le32_to_cpu(err->residual_count); + reply.sense_data_size = err->sense_response_data_len; + memcpy(reply.sense_data, err->sense_response_buf, + AAC_SENSE_BUFFERSIZE); + } + if (copy_to_user(user_reply, &reply, + sizeof(struct aac_srb_reply))) { + dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); + rcode = -EFAULT; + goto cleanup; + } + } else { + struct aac_srb_reply *reply; + + reply = (struct aac_srb_reply *) fib_data(srbfib); + if (copy_to_user(user_reply, reply, + sizeof(struct aac_srb_reply))) { + dprintk((KERN_DEBUG"aacraid: Copy to user failed\n")); + rcode = -EFAULT; + goto cleanup; + } } cleanup: kfree(user_srbcmd); - for(i=0; i <= sg_indx; i++){ - kfree(sg_list[i]); - } if (rcode != -ERESTARTSYS) { + for (i = 0; i <= sg_indx; i++) + kfree(sg_list[i]); aac_fib_complete(srbfib); aac_fib_free(srbfib); } @@ -858,6 +1013,44 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) return 0; } +static int aac_get_hba_info(struct aac_dev *dev, void __user *arg) +{ + struct aac_hba_info hbainfo; + + hbainfo.adapter_number = (u8) dev->id; + hbainfo.system_io_bus_number = dev->pdev->bus->number; + hbainfo.device_number = (dev->pdev->devfn >> 3); + hbainfo.function_number = (dev->pdev->devfn & 0x0007); + + hbainfo.vendor_id = dev->pdev->vendor; + hbainfo.device_id = dev->pdev->device; + hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; + hbainfo.sub_system_id = dev->pdev->subsystem_device; + + if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { + dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n")); + return -EFAULT; + } + + return 0; +} + +struct aac_reset_iop { + u8 reset_type; +}; + +static int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) +{ + struct aac_reset_iop reset; + int retval; + + if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) + return -EFAULT; + + retval = aac_reset_adapter(dev, 0, reset.reset_type); + return retval; + +} int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) { @@ -901,6 +1094,13 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) case FSACTL_GET_PCI_INFO: status = aac_get_pci_info(dev,arg); break; + case FSACTL_GET_HBA_INFO: + status = aac_get_hba_info(dev, arg); + break; + case FSACTL_RESET_IOP: + status = aac_send_reset_adapter(dev, arg); + break; + default: status = -ENOTTY; break; diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 5b48bedd7c38..40bfc57b6849 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,104 +73,175 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co unsigned long size, align; const unsigned long fibsize = dev->max_fib_size; const unsigned long printfbufsiz = 256; - unsigned long host_rrq_size = 0; - struct aac_init *init; + unsigned long host_rrq_size, aac_init_size; + union aac_init *init; dma_addr_t phys; unsigned long aac_max_hostphysmempages; - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 || - dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) + if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) || + (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) || + (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 && + !dev->sa_firmware)) { + host_rrq_size = + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + * sizeof(u32); + aac_init_size = sizeof(union aac_init); + } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 && + dev->sa_firmware) { host_rrq_size = (dev->scsi_host_ptr->can_queue - + AAC_NUM_MGT_FIB) * sizeof(u32); - size = fibsize + sizeof(struct aac_init) + commsize + - commalign + printfbufsiz + host_rrq_size; - + + AAC_NUM_MGT_FIB) * sizeof(u32) * AAC_MAX_MSIX; + aac_init_size = sizeof(union aac_init) + + (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq); + } else { + host_rrq_size = 0; + aac_init_size = sizeof(union aac_init); + } + size = fibsize + aac_init_size + commsize + commalign + + printfbufsiz + host_rrq_size; + base = pci_alloc_consistent(dev->pdev, size, &phys); - if(base == NULL) - { + if (base == NULL) { printk(KERN_ERR "aacraid: unable to create mapping.\n"); return 0; } + dev->comm_addr = (void *)base; dev->comm_phys = phys; dev->comm_size = size; - - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 || - dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { + + if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) || + (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) || + (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3)) { dev->host_rrq = (u32 *)(base + fibsize); dev->host_rrq_pa = phys + fibsize; memset(dev->host_rrq, 0, host_rrq_size); } - dev->init = (struct aac_init *)(base + fibsize + host_rrq_size); + dev->init = (union aac_init *)(base + fibsize + host_rrq_size); dev->init_pa = phys + fibsize + host_rrq_size; init = dev->init; - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); - if (dev->max_fib_size != sizeof(struct hw_fib)) - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4); - init->Sa_MSIXVectors = cpu_to_le32(SA_INIT_NUM_MSIXVECTORS); - init->fsrev = cpu_to_le32(dev->fsrev); + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { + int i; + u64 addr; + + init->r8.init_struct_revision = + cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_8); + init->r8.init_flags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED | + INITFLAGS_DRIVER_USES_UTC_TIME | + INITFLAGS_DRIVER_SUPPORTS_PM); + init->r8.init_flags |= + cpu_to_le32(INITFLAGS_DRIVER_SUPPORTS_HBA_MODE); + init->r8.rr_queue_count = cpu_to_le32(dev->max_msix); + init->r8.max_io_size = + cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); + init->r8.max_num_aif = init->r8.reserved1 = + init->r8.reserved2 = 0; + + for (i = 0; i < dev->max_msix; i++) { + addr = (u64)dev->host_rrq_pa + dev->vector_cap * i * + sizeof(u32); + init->r8.rrq[i].host_addr_high = cpu_to_le32( + upper_32_bits(addr)); + init->r8.rrq[i].host_addr_low = cpu_to_le32( + lower_32_bits(addr)); + init->r8.rrq[i].msix_id = i; + init->r8.rrq[i].element_count = cpu_to_le16( + (u16)dev->vector_cap); + init->r8.rrq[i].comp_thresh = + init->r8.rrq[i].unused = 0; + } - /* - * Adapter Fibs are the first thing allocated so that they - * start page aligned - */ - dev->aif_base_va = (struct hw_fib *)base; - - init->AdapterFibsVirtualAddress = 0; - init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); - init->AdapterFibsSize = cpu_to_le32(fibsize); - init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - /* - * number of 4k pages of host physical memory. The aacraid fw needs - * this number to be less than 4gb worth of pages. New firmware doesn't - * have any issues with the mapping system, but older Firmware did, and - * had *troubles* dealing with the math overloading past 32 bits, thus - * we must limit this field. - */ - aac_max_hostphysmempages = dma_get_required_mask(&dev->pdev->dev) >> 12; - if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES) - init->HostPhysMemPages = cpu_to_le32(aac_max_hostphysmempages); - else - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); - - init->InitFlags = cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | - INITFLAGS_DRIVER_SUPPORTS_PM); - init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); - init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); - init->MaxFibSize = cpu_to_le32(dev->max_fib_size); - init->MaxNumAif = cpu_to_le32(dev->max_num_aif); - - if (dev->comm_interface == AAC_COMM_MESSAGE) { - init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); - dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); - } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6); - init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED | - INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED); - init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32)); - init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff)); - dprintk((KERN_WARNING"aacraid: New Comm Interface type1 enabled\n")); - } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_7); - init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED | - INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED); - init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32)); - init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff)); - /* number of MSI-X */ - init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix); - dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n")); + pr_warn("aacraid: Comm Interface type3 enabled\n"); + } else { + init->r7.init_struct_revision = + cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); + if (dev->max_fib_size != sizeof(struct hw_fib)) + init->r7.init_struct_revision = + cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4); + init->r7.no_of_msix_vectors = cpu_to_le32(SA_MINIPORT_REVISION); + init->r7.fsrev = cpu_to_le32(dev->fsrev); + + /* + * Adapter Fibs are the first thing allocated so that they + * start page aligned + */ + dev->aif_base_va = (struct hw_fib *)base; + + init->r7.adapter_fibs_virtual_address = 0; + init->r7.adapter_fibs_physical_address = cpu_to_le32((u32)phys); + init->r7.adapter_fibs_size = cpu_to_le32(fibsize); + init->r7.adapter_fib_align = cpu_to_le32(sizeof(struct hw_fib)); + + /* + * number of 4k pages of host physical memory. The aacraid fw + * needs this number to be less than 4gb worth of pages. New + * firmware doesn't have any issues with the mapping system, but + * older Firmware did, and had *troubles* dealing with the math + * overloading past 32 bits, thus we must limit this field. + */ + aac_max_hostphysmempages = + dma_get_required_mask(&dev->pdev->dev) >> 12; + if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES) + init->r7.host_phys_mem_pages = + cpu_to_le32(aac_max_hostphysmempages); + else + init->r7.host_phys_mem_pages = + cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); + + init->r7.init_flags = + cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | + INITFLAGS_DRIVER_SUPPORTS_PM); + init->r7.max_io_commands = + cpu_to_le32(dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB); + init->r7.max_io_size = + cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); + init->r7.max_fib_size = cpu_to_le32(dev->max_fib_size); + init->r7.max_num_aif = cpu_to_le32(dev->max_num_aif); + + if (dev->comm_interface == AAC_COMM_MESSAGE) { + init->r7.init_flags |= + cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); + pr_warn("aacraid: Comm Interface enabled\n"); + } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { + init->r7.init_struct_revision = + cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6); + init->r7.init_flags |= + cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED | + INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | + INITFLAGS_FAST_JBOD_SUPPORTED); + init->r7.host_rrq_addr_high = + cpu_to_le32(upper_32_bits(dev->host_rrq_pa)); + init->r7.host_rrq_addr_low = + cpu_to_le32(lower_32_bits(dev->host_rrq_pa)); + pr_warn("aacraid: Comm Interface type1 enabled\n"); + } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { + init->r7.init_struct_revision = + cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_7); + init->r7.init_flags |= + cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED | + INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | + INITFLAGS_FAST_JBOD_SUPPORTED); + init->r7.host_rrq_addr_high = + cpu_to_le32(upper_32_bits(dev->host_rrq_pa)); + init->r7.host_rrq_addr_low = + cpu_to_le32(lower_32_bits(dev->host_rrq_pa)); + init->r7.no_of_msix_vectors = + cpu_to_le32(dev->max_msix); + /* must be the COMM_PREFERRED_SETTINGS values */ + pr_warn("aacraid: Comm Interface type2 enabled\n"); + } } /* * Increment the base address by the amount already used */ - base = base + fibsize + host_rrq_size + sizeof(struct aac_init); + base = base + fibsize + host_rrq_size + aac_init_size; phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size + - sizeof(struct aac_init)); + aac_init_size); /* * Align the beginning of Headers to commalign @@ -181,7 +253,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co * Fill in addresses of the Comm Area Headers and Queues */ *commaddr = base; - init->CommHeaderAddress = cpu_to_le32((u32)phys); + if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3) + init->r7.comm_header_address = cpu_to_le32((u32)phys); /* * Increment the base address by the size of the CommArea */ @@ -191,12 +264,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co * Place the Printf buffer area after the Fast I/O comm area. */ dev->printfbuf = (void *)base; - init->printfbuf = cpu_to_le32(phys); - init->printfbufsiz = cpu_to_le32(printfbufsiz); + if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3) { + init->r7.printfbuf = cpu_to_le32(phys); + init->r7.printfbufsiz = cpu_to_le32(printfbufsiz); + } memset(base, 0, printfbufsiz); return 1; } - + static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize) { atomic_set(&q->numpending, 0); @@ -404,9 +479,13 @@ void aac_define_int_mode(struct aac_dev *dev) if (dev->max_msix > msi_count) dev->max_msix = msi_count; } - dev->vector_cap = - (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) / - msi_count; + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 && dev->sa_firmware) + dev->vector_cap = dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB; + else + dev->vector_cap = (dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB) / msi_count; + } struct aac_dev *aac_init_adapter(struct aac_dev *dev) { @@ -440,30 +519,37 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 0, 0, 0, - status+0, status+1, status+2, status+3, NULL)) && - (status[0] == 0x00000001)) { + status+0, status+1, status+2, status+3, status+4)) && + (status[0] == 0x00000001)) { dev->doorbell_mask = status[3]; - if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) + if (status[1] & AAC_OPT_NEW_COMM_64) dev->raw_io_64 = 1; dev->sync_mode = aac_sync_mode; if (dev->a_ops.adapter_comm && - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) { + (status[1] & AAC_OPT_NEW_COMM)) { dev->comm_interface = AAC_COMM_MESSAGE; dev->raw_io_interface = 1; - if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) { + if ((status[1] & AAC_OPT_NEW_COMM_TYPE1)) { /* driver supports TYPE1 (Tupelo) */ dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; - } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) { - /* driver supports TYPE2 (Denali) */ + } else if (status[1] & AAC_OPT_NEW_COMM_TYPE2) { + /* driver supports TYPE2 (Denali, Yosemite) */ dev->comm_interface = AAC_COMM_MESSAGE_TYPE2; - } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) || - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3))) { - /* driver doesn't TYPE3 and TYPE4 */ - /* switch to sync. mode */ + } else if (status[1] & AAC_OPT_NEW_COMM_TYPE3) { + /* driver supports TYPE3 (Yosemite, Thor) */ + dev->comm_interface = AAC_COMM_MESSAGE_TYPE3; + } else if (status[1] & AAC_OPT_NEW_COMM_TYPE4) { + /* not supported TYPE - switch to sync. mode */ dev->comm_interface = AAC_COMM_MESSAGE_TYPE2; dev->sync_mode = 1; } } + if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) && + (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE))) + dev->sa_firmware = 1; + else + dev->sa_firmware = 0; + if ((dev->comm_interface == AAC_COMM_MESSAGE) && (status[2] > dev->base_size)) { aac_adapter_ioremap(dev, 0); @@ -500,61 +586,25 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) dev->sg_tablesize = status[2] & 0xFFFF; if (dev->pdev->device == PMC_DEVICE_S7 || dev->pdev->device == PMC_DEVICE_S8 || - dev->pdev->device == PMC_DEVICE_S9) - host->can_queue = ((status[3] >> 16) ? (status[3] >> 16) : - (status[3] & 0xFFFF)) - AAC_NUM_MGT_FIB; - else - host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB; + dev->pdev->device == PMC_DEVICE_S9) { + if (host->can_queue > (status[3] >> 16) - + AAC_NUM_MGT_FIB) + host->can_queue = (status[3] >> 16) - + AAC_NUM_MGT_FIB; + } else if (host->can_queue > (status[3] & 0xFFFF) - + AAC_NUM_MGT_FIB) + host->can_queue = (status[3] & 0xFFFF) - + AAC_NUM_MGT_FIB; + dev->max_num_aif = status[4] & 0xFFFF; - /* - * NOTE: - * All these overrides are based on a fixed internal - * knowledge and understanding of existing adapters, - * acbsize should be set with caution. - */ - if (acbsize == 512) { - host->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - dev->max_fib_size = 512; - dev->sg_tablesize = host->sg_tablesize - = (512 - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) - / sizeof(struct sgentry); - host->can_queue = AAC_NUM_IO_FIB; - } else if (acbsize == 2048) { - host->max_sectors = 512; - dev->max_fib_size = 2048; - host->sg_tablesize = 65; - dev->sg_tablesize = 81; - host->can_queue = 512 - AAC_NUM_MGT_FIB; - } else if (acbsize == 4096) { - host->max_sectors = 1024; - dev->max_fib_size = 4096; - host->sg_tablesize = 129; - dev->sg_tablesize = 166; - host->can_queue = 256 - AAC_NUM_MGT_FIB; - } else if (acbsize == 8192) { - host->max_sectors = 2048; - dev->max_fib_size = 8192; - host->sg_tablesize = 257; - dev->sg_tablesize = 337; - host->can_queue = 128 - AAC_NUM_MGT_FIB; - } else if (acbsize > 0) { - printk("Illegal acbsize=%d ignored\n", acbsize); - } } - { - - if (numacb > 0) { - if (numacb < host->can_queue) - host->can_queue = numacb; - else - printk("numacb=%d ignored\n", numacb); - } + if (numacb > 0) { + if (numacb < host->can_queue) + host->can_queue = numacb; + else + pr_warn("numacb=%d ignored\n", numacb); } - if (host->can_queue > AAC_NUM_IO_FIB) - host->can_queue = AAC_NUM_IO_FIB; - if (dev->pdev->device == PMC_DEVICE_S6 || dev->pdev->device == PMC_DEVICE_S7 || dev->pdev->device == PMC_DEVICE_S8 || diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 9e7551fe4b19..969727b67cdd 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +44,7 @@ #include <linux/kthread.h> #include <linux/interrupt.h> #include <linux/semaphore.h> +#include <linux/bcd.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_device.h> @@ -60,12 +62,22 @@ static int fib_map_alloc(struct aac_dev *dev) { + if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE) + dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; + else + dev->max_cmd_size = dev->max_fib_size; + if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) { + dev->max_cmd_size = AAC_MAX_NATIVE_SIZE; + } else { + dev->max_cmd_size = dev->max_fib_size; + } + dprintk((KERN_INFO "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", - dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, + dev->pdev, dev->max_cmd_size, dev->scsi_host_ptr->can_queue, AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); dev->hw_fib_va = pci_alloc_consistent(dev->pdev, - (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) + (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), &dev->hw_fib_pa); if (dev->hw_fib_va == NULL) @@ -83,9 +95,9 @@ static int fib_map_alloc(struct aac_dev *dev) void aac_fib_map_free(struct aac_dev *dev) { - if (dev->hw_fib_va && dev->max_fib_size) { + if (dev->hw_fib_va && dev->max_cmd_size) { pci_free_consistent(dev->pdev, - (dev->max_fib_size * + (dev->max_cmd_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)), dev->hw_fib_va, dev->hw_fib_pa); } @@ -129,11 +141,14 @@ int aac_fib_setup(struct aac_dev * dev) struct hw_fib *hw_fib; dma_addr_t hw_fib_pa; int i; + u32 max_cmds; while (((i = fib_map_alloc(dev)) == -ENOMEM) && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) { - dev->init->MaxIoCommands = cpu_to_le32((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) >> 1); - dev->scsi_host_ptr->can_queue = le32_to_cpu(dev->init->MaxIoCommands) - AAC_NUM_MGT_FIB; + max_cmds = (dev->scsi_host_ptr->can_queue+AAC_NUM_MGT_FIB) >> 1; + dev->scsi_host_ptr->can_queue = max_cmds - AAC_NUM_MGT_FIB; + if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3) + dev->init->r7.max_io_commands = cpu_to_le32(max_cmds); } if (i<0) return -ENOMEM; @@ -144,7 +159,7 @@ int aac_fib_setup(struct aac_dev * dev) (hw_fib_pa - dev->hw_fib_pa)); dev->hw_fib_pa = hw_fib_pa; memset(dev->hw_fib_va, 0, - (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * + (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); /* add Xport header */ @@ -170,12 +185,22 @@ int aac_fib_setup(struct aac_dev * dev) sema_init(&fibptr->event_wait, 0); spin_lock_init(&fibptr->event_lock); hw_fib->header.XferState = cpu_to_le32(0xffffffff); - hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); + hw_fib->header.SenderSize = + cpu_to_le16(dev->max_fib_size); /* ?? max_cmd_size */ fibptr->hw_fib_pa = hw_fib_pa; + fibptr->hw_sgl_pa = hw_fib_pa + + offsetof(struct aac_hba_cmd_req, sge[2]); + /* + * one element is for the ptr to the separate sg list, + * second element for 32 byte alignment + */ + fibptr->hw_error_pa = hw_fib_pa + + offsetof(struct aac_native_hba, resp.resp_bytes[0]); + hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + - dev->max_fib_size + sizeof(struct aac_fib_xporthdr)); + dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)); hw_fib_pa = hw_fib_pa + - dev->max_fib_size + sizeof(struct aac_fib_xporthdr); + dev->max_cmd_size + sizeof(struct aac_fib_xporthdr); } /* @@ -273,7 +298,8 @@ void aac_fib_free(struct fib *fibptr) spin_lock_irqsave(&fibptr->dev->fib_lock, flags); if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) aac_config.fib_timeouts++; - if (fibptr->hw_fib_va->header.XferState != 0) { + if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) && + fibptr->hw_fib_va->header.XferState != 0) { printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", (void*)fibptr, le32_to_cpu(fibptr->hw_fib_va->header.XferState)); @@ -501,8 +527,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, * Map the fib into 32bits by using the fib number */ - hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2); - hw_fib->header.Handle = (u32)(fibptr - dev->fibs) + 1; + hw_fib->header.SenderFibAddress = + cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2); + + /* use the same shifted value for handle to be compatible + * with the new native hba command handle + */ + hw_fib->header.Handle = + cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); + /* * Set FIB state to indicate where it came from and if we want a * response from the adapter. Also load the command from the @@ -670,6 +703,82 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, return 0; } +int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback, + void *callback_data) +{ + struct aac_dev *dev = fibptr->dev; + int wait; + unsigned long flags = 0; + unsigned long mflags = 0; + + fibptr->flags = (FIB_CONTEXT_FLAG | FIB_CONTEXT_FLAG_NATIVE_HBA); + if (callback) { + wait = 0; + fibptr->callback = callback; + fibptr->callback_data = callback_data; + } else + wait = 1; + + + if (command == HBA_IU_TYPE_SCSI_CMD_REQ) { + struct aac_hba_cmd_req *hbacmd = + (struct aac_hba_cmd_req *)fibptr->hw_fib_va; + + hbacmd->iu_type = command; + /* bit1 of request_id must be 0 */ + hbacmd->request_id = + cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1); + } else + return -EINVAL; + + + if (wait) { + spin_lock_irqsave(&dev->manage_lock, mflags); + if (dev->management_fib_count >= AAC_NUM_MGT_FIB) { + spin_unlock_irqrestore(&dev->manage_lock, mflags); + return -EBUSY; + } + dev->management_fib_count++; + spin_unlock_irqrestore(&dev->manage_lock, mflags); + spin_lock_irqsave(&fibptr->event_lock, flags); + } + + if (aac_adapter_deliver(fibptr) != 0) { + if (wait) { + spin_unlock_irqrestore(&fibptr->event_lock, flags); + spin_lock_irqsave(&dev->manage_lock, mflags); + dev->management_fib_count--; + spin_unlock_irqrestore(&dev->manage_lock, mflags); + } + return -EBUSY; + } + FIB_COUNTER_INCREMENT(aac_config.NativeSent); + + if (wait) { + spin_unlock_irqrestore(&fibptr->event_lock, flags); + /* Only set for first known interruptable command */ + if (down_interruptible(&fibptr->event_wait)) { + fibptr->done = 2; + up(&fibptr->event_wait); + } + spin_lock_irqsave(&fibptr->event_lock, flags); + if ((fibptr->done == 0) || (fibptr->done == 2)) { + fibptr->done = 2; /* Tell interrupt we aborted */ + spin_unlock_irqrestore(&fibptr->event_lock, flags); + return -ERESTARTSYS; + } + spin_unlock_irqrestore(&fibptr->event_lock, flags); + WARN_ON(fibptr->done == 0); + + if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) + return -ETIMEDOUT; + + return 0; + } + + return -EINPROGRESS; +} + /** * aac_consumer_get - get the top of the queue * @dev: Adapter @@ -761,7 +870,8 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) unsigned long qflags; if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 || - dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { + dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || + dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { kfree(hw_fib); return 0; } @@ -827,11 +937,17 @@ int aac_fib_complete(struct fib *fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib_va; + if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) { + fib_dealloc(fibptr); + return 0; + } + /* - * Check for a fib which has already been completed + * Check for a fib which has already been completed or with a + * status wait timeout */ - if (hw_fib->header.XferState == 0) + if (hw_fib->header.XferState == 0 || fibptr->done == 2) return 0; /* * If we plan to do anything check the structure type first. @@ -984,20 +1100,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) lun = (container >> 16) & 0xFF; container = (u32)-1; channel = aac_phys_to_logical(channel); - device_config_needed = - (((__le32 *)aifcmd->data)[0] == - cpu_to_le32(AifRawDeviceRemove)) ? DELETE : ADD; - - if (device_config_needed == ADD) { - device = scsi_device_lookup( - dev->scsi_host_ptr, - channel, id, lun); - if (device) { - scsi_remove_device(device); - scsi_device_put(device); - } - } + device_config_needed = DELETE; break; + /* * Morph or Expand complete */ @@ -1351,7 +1456,7 @@ retry_next: } } -static int _aac_reset_adapter(struct aac_dev *aac, int forced) +static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) { int index, quirks; int retval; @@ -1360,6 +1465,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) struct scsi_cmnd *command; struct scsi_cmnd *command_list; int jafo = 0; + int bled; /* * Assumptions: @@ -1384,7 +1490,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) * If a positive health, means in a known DEAD PANIC * state and the adapter could be reset to `try again'. */ - retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac)); + bled = forced ? 0 : aac_adapter_check_health(aac); + retval = aac_adapter_restart(aac, bled, reset_type); if (retval) goto out; @@ -1494,11 +1601,12 @@ out: return retval; } -int aac_reset_adapter(struct aac_dev * aac, int forced) +int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) { unsigned long flagv = 0; int retval; struct Scsi_Host * host; + int bled; if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) return -EBUSY; @@ -1547,7 +1655,9 @@ int aac_reset_adapter(struct aac_dev * aac, int forced) if (forced < 2) aac_send_shutdown(aac); spin_lock_irqsave(host->host_lock, flagv); - retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1))); + bled = forced ? forced : + (aac_check_reset != 0 && aac_check_reset != 1); + retval = _aac_reset_adapter(aac, bled, reset_type); spin_unlock_irqrestore(host->host_lock, flagv); if ((forced < 2) && (retval == -ENODEV)) { @@ -1593,6 +1703,7 @@ int aac_check_health(struct aac_dev * aac) unsigned long time_now, flagv = 0; struct list_head * entry; struct Scsi_Host * host; + int bled; /* Extending the scope of fib_lock slightly to protect aac->in_reset */ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) @@ -1710,7 +1821,8 @@ int aac_check_health(struct aac_dev * aac) host = aac->scsi_host_ptr; if (aac->thread->pid != current->pid) spin_lock_irqsave(host->host_lock, flagv); - BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1); + bled = aac_check_reset != 1 ? 1 : 0; + _aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET); if (aac->thread->pid != current->pid) spin_unlock_irqrestore(host->host_lock, flagv); return BlinkLED; @@ -1721,6 +1833,552 @@ out: } +static void aac_resolve_luns(struct aac_dev *dev) +{ + int bus, target, channel; + struct scsi_device *sdev; + u8 devtype; + u8 new_devtype; + + for (bus = 0; bus < AAC_MAX_BUSES; bus++) { + for (target = 0; target < AAC_MAX_TARGETS; target++) { + + if (aac_phys_to_logical(bus) == ENCLOSURE_CHANNEL) + continue; + + if (bus == CONTAINER_CHANNEL) + channel = CONTAINER_CHANNEL; + else + channel = aac_phys_to_logical(bus); + + devtype = dev->hba_map[bus][target].devtype; + new_devtype = dev->hba_map[bus][target].new_devtype; + + sdev = scsi_device_lookup(dev->scsi_host_ptr, channel, + target, 0); + + if (!sdev && devtype) + scsi_add_device(dev->scsi_host_ptr, channel, + target, 0); + else if (sdev && new_devtype != devtype) + scsi_remove_device(sdev); + else if (sdev && new_devtype == devtype) + scsi_rescan_device(&sdev->sdev_gendev); + + if (sdev) + scsi_device_put(sdev); + + dev->hba_map[bus][target].devtype = new_devtype; + } + } +} + +/** + * aac_handle_sa_aif Handle a message from the firmware + * @dev: Which adapter this fib is from + * @fibptr: Pointer to fibptr from adapter + * + * This routine handles a driver notify fib from the adapter and + * dispatches it to the appropriate routine for handling. + */ +static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr) +{ + int i, bus, target, container, rcode = 0; + u32 events = 0; + struct fib *fib; + struct scsi_device *sdev; + + if (fibptr->hbacmd_size & SA_AIF_HOTPLUG) + events = SA_AIF_HOTPLUG; + else if (fibptr->hbacmd_size & SA_AIF_HARDWARE) + events = SA_AIF_HARDWARE; + else if (fibptr->hbacmd_size & SA_AIF_PDEV_CHANGE) + events = SA_AIF_PDEV_CHANGE; + else if (fibptr->hbacmd_size & SA_AIF_LDEV_CHANGE) + events = SA_AIF_LDEV_CHANGE; + else if (fibptr->hbacmd_size & SA_AIF_BPSTAT_CHANGE) + events = SA_AIF_BPSTAT_CHANGE; + else if (fibptr->hbacmd_size & SA_AIF_BPCFG_CHANGE) + events = SA_AIF_BPCFG_CHANGE; + + switch (events) { + case SA_AIF_HOTPLUG: + case SA_AIF_HARDWARE: + case SA_AIF_PDEV_CHANGE: + case SA_AIF_LDEV_CHANGE: + case SA_AIF_BPCFG_CHANGE: + + fib = aac_fib_alloc(dev); + if (!fib) { + pr_err("aac_handle_sa_aif: out of memory\n"); + return; + } + for (bus = 0; bus < AAC_MAX_BUSES; bus++) + for (target = 0; target < AAC_MAX_TARGETS; target++) + dev->hba_map[bus][target].new_devtype = 0; + + rcode = aac_report_phys_luns(dev, fib, AAC_RESCAN); + + if (rcode != -ERESTARTSYS) + aac_fib_free(fib); + + aac_resolve_luns(dev); + + if (events == SA_AIF_LDEV_CHANGE || + events == SA_AIF_BPCFG_CHANGE) { + aac_get_containers(dev); + for (container = 0; container < + dev->maximum_num_containers; ++container) { + sdev = scsi_device_lookup(dev->scsi_host_ptr, + CONTAINER_CHANNEL, + container, 0); + if (dev->fsa_dev[container].valid && !sdev) { + scsi_add_device(dev->scsi_host_ptr, + CONTAINER_CHANNEL, + container, 0); + } else if (!dev->fsa_dev[container].valid && + sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else if (sdev) { + scsi_rescan_device(&sdev->sdev_gendev); + scsi_device_put(sdev); + } + } + } + break; + + case SA_AIF_BPSTAT_CHANGE: + /* currently do nothing */ + break; + } + + for (i = 1; i <= 10; ++i) { + events = src_readl(dev, MUnit.IDR); + if (events & (1<<23)) { + pr_warn(" AIF not cleared by firmware - %d/%d)\n", + i, 10); + ssleep(1); + } + } +} + +static int get_fib_count(struct aac_dev *dev) +{ + unsigned int num = 0; + struct list_head *entry; + unsigned long flagv; + + /* + * Warning: no sleep allowed while + * holding spinlock. We take the estimate + * and pre-allocate a set of fibs outside the + * lock. + */ + num = le32_to_cpu(dev->init->r7.adapter_fibs_size) + / sizeof(struct hw_fib); /* some extra */ + spin_lock_irqsave(&dev->fib_lock, flagv); + entry = dev->fib_list.next; + while (entry != &dev->fib_list) { + entry = entry->next; + ++num; + } + spin_unlock_irqrestore(&dev->fib_lock, flagv); + + return num; +} + +static int fillup_pools(struct aac_dev *dev, struct hw_fib **hw_fib_pool, + struct fib **fib_pool, + unsigned int num) +{ + struct hw_fib **hw_fib_p; + struct fib **fib_p; + int rcode = 1; + + hw_fib_p = hw_fib_pool; + fib_p = fib_pool; + while (hw_fib_p < &hw_fib_pool[num]) { + *(hw_fib_p) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL); + if (!(*(hw_fib_p++))) { + --hw_fib_p; + break; + } + + *(fib_p) = kmalloc(sizeof(struct fib), GFP_KERNEL); + if (!(*(fib_p++))) { + kfree(*(--hw_fib_p)); + break; + } + } + + num = hw_fib_p - hw_fib_pool; + if (!num) + rcode = 0; + + return rcode; +} + +static void wakeup_fibctx_threads(struct aac_dev *dev, + struct hw_fib **hw_fib_pool, + struct fib **fib_pool, + struct fib *fib, + struct hw_fib *hw_fib, + unsigned int num) +{ + unsigned long flagv; + struct list_head *entry; + struct hw_fib **hw_fib_p; + struct fib **fib_p; + u32 time_now, time_last; + struct hw_fib *hw_newfib; + struct fib *newfib; + struct aac_fib_context *fibctx; + + time_now = jiffies/HZ; + spin_lock_irqsave(&dev->fib_lock, flagv); + entry = dev->fib_list.next; + /* + * For each Context that is on the + * fibctxList, make a copy of the + * fib, and then set the event to wake up the + * thread that is waiting for it. + */ + + hw_fib_p = hw_fib_pool; + fib_p = fib_pool; + while (entry != &dev->fib_list) { + /* + * Extract the fibctx + */ + fibctx = list_entry(entry, struct aac_fib_context, + next); + /* + * Check if the queue is getting + * backlogged + */ + if (fibctx->count > 20) { + /* + * It's *not* jiffies folks, + * but jiffies / HZ so do not + * panic ... + */ + time_last = fibctx->jiffies; + /* + * Has it been > 2 minutes + * since the last read off + * the queue? + */ + if ((time_now - time_last) > aif_timeout) { + entry = entry->next; + aac_close_fib_context(dev, fibctx); + continue; + } + } + /* + * Warning: no sleep allowed while + * holding spinlock + */ + if (hw_fib_p >= &hw_fib_pool[num]) { + pr_warn("aifd: didn't allocate NewFib\n"); + entry = entry->next; + continue; + } + + hw_newfib = *hw_fib_p; + *(hw_fib_p++) = NULL; + newfib = *fib_p; + *(fib_p++) = NULL; + /* + * Make the copy of the FIB + */ + memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib)); + memcpy(newfib, fib, sizeof(struct fib)); + newfib->hw_fib_va = hw_newfib; + /* + * Put the FIB onto the + * fibctx's fibs + */ + list_add_tail(&newfib->fiblink, &fibctx->fib_list); + fibctx->count++; + /* + * Set the event to wake up the + * thread that is waiting. + */ + up(&fibctx->wait_sem); + + entry = entry->next; + } + /* + * Set the status of this FIB + */ + *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); + aac_fib_adapter_complete(fib, sizeof(u32)); + spin_unlock_irqrestore(&dev->fib_lock, flagv); + +} + +static void aac_process_events(struct aac_dev *dev) +{ + struct hw_fib *hw_fib; + struct fib *fib; + unsigned long flags; + spinlock_t *t_lock; + unsigned int rcode; + + t_lock = dev->queues->queue[HostNormCmdQueue].lock; + spin_lock_irqsave(t_lock, flags); + + while (!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) { + struct list_head *entry; + struct aac_aifcmd *aifcmd; + unsigned int num; + struct hw_fib **hw_fib_pool, **hw_fib_p; + struct fib **fib_pool, **fib_p; + + set_current_state(TASK_RUNNING); + + entry = dev->queues->queue[HostNormCmdQueue].cmdq.next; + list_del(entry); + + t_lock = dev->queues->queue[HostNormCmdQueue].lock; + spin_unlock_irqrestore(t_lock, flags); + + fib = list_entry(entry, struct fib, fiblink); + hw_fib = fib->hw_fib_va; + if (dev->sa_firmware) { + /* Thor AIF */ + aac_handle_sa_aif(dev, fib); + aac_fib_adapter_complete(fib, (u16)sizeof(u32)); + continue; + } + /* + * We will process the FIB here or pass it to a + * worker thread that is TBD. We Really can't + * do anything at this point since we don't have + * anything defined for this thread to do. + */ + memset(fib, 0, sizeof(struct fib)); + fib->type = FSAFS_NTC_FIB_CONTEXT; + fib->size = sizeof(struct fib); + fib->hw_fib_va = hw_fib; + fib->data = hw_fib->data; + fib->dev = dev; + /* + * We only handle AifRequest fibs from the adapter. + */ + + aifcmd = (struct aac_aifcmd *) hw_fib->data; + if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { + /* Handle Driver Notify Events */ + aac_handle_aif(dev, fib); + *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); + aac_fib_adapter_complete(fib, (u16)sizeof(u32)); + goto free_fib; + } + /* + * The u32 here is important and intended. We are using + * 32bit wrapping time to fit the adapter field + */ + + /* Sniff events */ + if (aifcmd->command == cpu_to_le32(AifCmdEventNotify) + || aifcmd->command == cpu_to_le32(AifCmdJobProgress)) { + aac_handle_aif(dev, fib); + } + + /* + * get number of fibs to process + */ + num = get_fib_count(dev); + if (!num) + goto free_fib; + + hw_fib_pool = kmalloc_array(num, sizeof(struct hw_fib *), + GFP_KERNEL); + if (!hw_fib_pool) + goto free_fib; + + fib_pool = kmalloc_array(num, sizeof(struct fib *), GFP_KERNEL); + if (!fib_pool) + goto free_hw_fib_pool; + + /* + * Fill up fib pointer pools with actual fibs + * and hw_fibs + */ + rcode = fillup_pools(dev, hw_fib_pool, fib_pool, num); + if (!rcode) + goto free_mem; + + /* + * wakeup the thread that is waiting for + * the response from fw (ioctl) + */ + wakeup_fibctx_threads(dev, hw_fib_pool, fib_pool, + fib, hw_fib, num); + +free_mem: + /* Free up the remaining resources */ + hw_fib_p = hw_fib_pool; + fib_p = fib_pool; + while (hw_fib_p < &hw_fib_pool[num]) { + kfree(*hw_fib_p); + kfree(*fib_p); + ++fib_p; + ++hw_fib_p; + } + kfree(fib_pool); +free_hw_fib_pool: + kfree(hw_fib_pool); +free_fib: + kfree(fib); + t_lock = dev->queues->queue[HostNormCmdQueue].lock; + spin_lock_irqsave(t_lock, flags); + } + /* + * There are no more AIF's + */ + t_lock = dev->queues->queue[HostNormCmdQueue].lock; + spin_unlock_irqrestore(t_lock, flags); +} + +static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str, + u32 datasize) +{ + struct aac_srb *srbcmd; + struct sgmap64 *sg64; + dma_addr_t addr; + char *dma_buf; + struct fib *fibptr; + int ret = -ENOMEM; + u32 vbus, vid; + + fibptr = aac_fib_alloc(dev); + if (!fibptr) + goto out; + + dma_buf = pci_alloc_consistent(dev->pdev, datasize, &addr); + if (!dma_buf) + goto fib_free_out; + + aac_fib_init(fibptr); + + vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus); + vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget); + + srbcmd = (struct aac_srb *)fib_data(fibptr); + + srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); + srbcmd->channel = cpu_to_le32(vbus); + srbcmd->id = cpu_to_le32(vid); + srbcmd->lun = 0; + srbcmd->flags = cpu_to_le32(SRB_DataOut); + srbcmd->timeout = cpu_to_le32(10); + srbcmd->retry_limit = 0; + srbcmd->cdb_size = cpu_to_le32(12); + srbcmd->count = cpu_to_le32(datasize); + + memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); + srbcmd->cdb[0] = BMIC_OUT; + srbcmd->cdb[6] = WRITE_HOST_WELLNESS; + memcpy(dma_buf, (char *)wellness_str, datasize); + + sg64 = (struct sgmap64 *)&srbcmd->sg; + sg64->count = cpu_to_le32(1); + sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16)); + sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + sg64->sg[0].count = cpu_to_le32(datasize); + + ret = aac_fib_send(ScsiPortCommand64, fibptr, sizeof(struct aac_srb), + FsaNormal, 1, 1, NULL, NULL); + + pci_free_consistent(dev->pdev, datasize, (void *)dma_buf, addr); + + /* + * Do not set XferState to zero unless + * receives a response from F/W + */ + if (ret >= 0) + aac_fib_complete(fibptr); + + /* + * FIB should be freed only after + * getting the response from the F/W + */ + if (ret != -ERESTARTSYS) + goto fib_free_out; + +out: + return ret; +fib_free_out: + aac_fib_free(fibptr); + goto out; +} + +int aac_send_safw_hostttime(struct aac_dev *dev, struct timeval *now) +{ + struct tm cur_tm; + char wellness_str[] = "<HW>TD\010\0\0\0\0\0\0\0\0\0DW\0\0ZZ"; + u32 datasize = sizeof(wellness_str); + unsigned long local_time; + int ret = -ENODEV; + + if (!dev->sa_firmware) + goto out; + + local_time = (u32)(now->tv_sec - (sys_tz.tz_minuteswest * 60)); + time_to_tm(local_time, 0, &cur_tm); + cur_tm.tm_mon += 1; + cur_tm.tm_year += 1900; + wellness_str[8] = bin2bcd(cur_tm.tm_hour); + wellness_str[9] = bin2bcd(cur_tm.tm_min); + wellness_str[10] = bin2bcd(cur_tm.tm_sec); + wellness_str[12] = bin2bcd(cur_tm.tm_mon); + wellness_str[13] = bin2bcd(cur_tm.tm_mday); + wellness_str[14] = bin2bcd(cur_tm.tm_year / 100); + wellness_str[15] = bin2bcd(cur_tm.tm_year % 100); + + ret = aac_send_wellness_command(dev, wellness_str, datasize); + +out: + return ret; +} + +int aac_send_hosttime(struct aac_dev *dev, struct timeval *now) +{ + int ret = -ENOMEM; + struct fib *fibptr; + __le32 *info; + + fibptr = aac_fib_alloc(dev); + if (!fibptr) + goto out; + + aac_fib_init(fibptr); + info = (__le32 *)fib_data(fibptr); + *info = cpu_to_le32(now->tv_sec); + ret = aac_fib_send(SendHostTime, fibptr, sizeof(*info), FsaNormal, + 1, 1, NULL, NULL); + + /* + * Do not set XferState to zero unless + * receives a response from F/W + */ + if (ret >= 0) + aac_fib_complete(fibptr); + + /* + * FIB should be freed only after + * getting the response from the F/W + */ + if (ret != -ERESTARTSYS) + aac_fib_free(fibptr); + +out: + return ret; +} + /** * aac_command_thread - command processing thread * @dev: Adapter to monitor @@ -1734,10 +2392,6 @@ out: int aac_command_thread(void *data) { struct aac_dev *dev = data; - struct hw_fib *hw_fib, *hw_newfib; - struct fib *fib, *newfib; - struct aac_fib_context *fibctx; - unsigned long flags; DECLARE_WAITQUEUE(wait, current); unsigned long next_jiffies = jiffies + HZ; unsigned long next_check_jiffies = next_jiffies; @@ -1757,196 +2411,8 @@ int aac_command_thread(void *data) set_current_state(TASK_INTERRUPTIBLE); dprintk ((KERN_INFO "aac_command_thread start\n")); while (1) { - spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); - while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) { - struct list_head *entry; - struct aac_aifcmd * aifcmd; - - set_current_state(TASK_RUNNING); - entry = dev->queues->queue[HostNormCmdQueue].cmdq.next; - list_del(entry); - - spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); - fib = list_entry(entry, struct fib, fiblink); - /* - * We will process the FIB here or pass it to a - * worker thread that is TBD. We Really can't - * do anything at this point since we don't have - * anything defined for this thread to do. - */ - hw_fib = fib->hw_fib_va; - memset(fib, 0, sizeof(struct fib)); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; - fib->data = hw_fib->data; - fib->dev = dev; - /* - * We only handle AifRequest fibs from the adapter. - */ - aifcmd = (struct aac_aifcmd *) hw_fib->data; - if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { - /* Handle Driver Notify Events */ - aac_handle_aif(dev, fib); - *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); - aac_fib_adapter_complete(fib, (u16)sizeof(u32)); - } else { - /* The u32 here is important and intended. We are using - 32bit wrapping time to fit the adapter field */ - - u32 time_now, time_last; - unsigned long flagv; - unsigned num; - struct hw_fib ** hw_fib_pool, ** hw_fib_p; - struct fib ** fib_pool, ** fib_p; - - /* Sniff events */ - if ((aifcmd->command == - cpu_to_le32(AifCmdEventNotify)) || - (aifcmd->command == - cpu_to_le32(AifCmdJobProgress))) { - aac_handle_aif(dev, fib); - } - - time_now = jiffies/HZ; - - /* - * Warning: no sleep allowed while - * holding spinlock. We take the estimate - * and pre-allocate a set of fibs outside the - * lock. - */ - num = le32_to_cpu(dev->init->AdapterFibsSize) - / sizeof(struct hw_fib); /* some extra */ - spin_lock_irqsave(&dev->fib_lock, flagv); - entry = dev->fib_list.next; - while (entry != &dev->fib_list) { - entry = entry->next; - ++num; - } - spin_unlock_irqrestore(&dev->fib_lock, flagv); - hw_fib_pool = NULL; - fib_pool = NULL; - if (num - && ((hw_fib_pool = kmalloc(sizeof(struct hw_fib *) * num, GFP_KERNEL))) - && ((fib_pool = kmalloc(sizeof(struct fib *) * num, GFP_KERNEL)))) { - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (hw_fib_p < &hw_fib_pool[num]) { - if (!(*(hw_fib_p++) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL))) { - --hw_fib_p; - break; - } - if (!(*(fib_p++) = kmalloc(sizeof(struct fib), GFP_KERNEL))) { - kfree(*(--hw_fib_p)); - break; - } - } - if ((num = hw_fib_p - hw_fib_pool) == 0) { - kfree(fib_pool); - fib_pool = NULL; - kfree(hw_fib_pool); - hw_fib_pool = NULL; - } - } else { - kfree(hw_fib_pool); - hw_fib_pool = NULL; - } - spin_lock_irqsave(&dev->fib_lock, flagv); - entry = dev->fib_list.next; - /* - * For each Context that is on the - * fibctxList, make a copy of the - * fib, and then set the event to wake up the - * thread that is waiting for it. - */ - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (entry != &dev->fib_list) { - /* - * Extract the fibctx - */ - fibctx = list_entry(entry, struct aac_fib_context, next); - /* - * Check if the queue is getting - * backlogged - */ - if (fibctx->count > 20) - { - /* - * It's *not* jiffies folks, - * but jiffies / HZ so do not - * panic ... - */ - time_last = fibctx->jiffies; - /* - * Has it been > 2 minutes - * since the last read off - * the queue? - */ - if ((time_now - time_last) > aif_timeout) { - entry = entry->next; - aac_close_fib_context(dev, fibctx); - continue; - } - } - /* - * Warning: no sleep allowed while - * holding spinlock - */ - if (hw_fib_p < &hw_fib_pool[num]) { - hw_newfib = *hw_fib_p; - *(hw_fib_p++) = NULL; - newfib = *fib_p; - *(fib_p++) = NULL; - /* - * Make the copy of the FIB - */ - memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib)); - memcpy(newfib, fib, sizeof(struct fib)); - newfib->hw_fib_va = hw_newfib; - /* - * Put the FIB onto the - * fibctx's fibs - */ - list_add_tail(&newfib->fiblink, &fibctx->fib_list); - fibctx->count++; - /* - * Set the event to wake up the - * thread that is waiting. - */ - up(&fibctx->wait_sem); - } else { - printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); - } - entry = entry->next; - } - /* - * Set the status of this FIB - */ - *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); - aac_fib_adapter_complete(fib, sizeof(u32)); - spin_unlock_irqrestore(&dev->fib_lock, flagv); - /* Free up the remaining resources */ - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (hw_fib_p < &hw_fib_pool[num]) { - kfree(*hw_fib_p); - kfree(*fib_p); - ++fib_p; - ++hw_fib_p; - } - kfree(hw_fib_pool); - kfree(fib_pool); - } - kfree(fib); - spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); - } - /* - * There are no more AIF's - */ - spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); + aac_process_events(dev); /* * Background activity @@ -1968,7 +2434,7 @@ int aac_command_thread(void *data) /* Don't even try to talk to adapter if its sick */ ret = aac_check_health(dev); - if (!ret && !dev->queues) + if (!dev->queues) break; next_check_jiffies = jiffies + ((long)(unsigned)check_interval) @@ -1981,36 +2447,16 @@ int aac_command_thread(void *data) difference = (((1000000 - now.tv_usec) * HZ) + 500000) / 1000000; else if (ret == 0) { - struct fib *fibptr; - - if ((fibptr = aac_fib_alloc(dev))) { - int status; - __le32 *info; - - aac_fib_init(fibptr); - - info = (__le32 *) fib_data(fibptr); - if (now.tv_usec > 500000) - ++now.tv_sec; - - *info = cpu_to_le32(now.tv_sec); - - status = aac_fib_send(SendHostTime, - fibptr, - sizeof(*info), - FsaNormal, - 1, 1, - NULL, - NULL); - /* Do not set XferState to zero unless - * receives a response from F/W */ - if (status >= 0) - aac_fib_complete(fibptr); - /* FIB should be freed only after - * getting the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibptr); - } + + if (now.tv_usec > 500000) + ++now.tv_sec; + + if (dev->sa_firmware) + ret = + aac_send_safw_hostttime(dev, &now); + else + ret = aac_send_hosttime(dev, &now); + difference = (long)(unsigned)update_interval*HZ; } else { /* retry shortly */ diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 7e836205aef1..417ba349e10e 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -122,7 +123,6 @@ unsigned int aac_response_normal(struct aac_queue * q) * NOTE: we cannot touch the fib after this * call, because it may have been deallocated. */ - fib->flags &= FIB_CONTEXT_FLAG_FASTRESP; fib->callback(fib->callback_data, fib); } else { unsigned long flagv; @@ -251,8 +251,9 @@ static void aac_aif_callback(void *context, struct fib * fibptr) BUG_ON(fibptr == NULL); dev = fibptr->dev; - if (fibptr->hw_fib_va->header.XferState & - cpu_to_le32(NoMoreAifDataAvailable)) { + if ((fibptr->hw_fib_va->header.XferState & + cpu_to_le32(NoMoreAifDataAvailable)) || + dev->sa_firmware) { aac_fib_complete(fibptr); aac_fib_free(fibptr); return; @@ -282,8 +283,8 @@ static void aac_aif_callback(void *context, struct fib * fibptr) * know there is a response on our normal priority queue. We will pull off * all QE there are and wake up all the waiters before exiting. */ -unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, - int isAif, int isFastResponse, struct hw_fib *aif_fib) +unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif, + int isFastResponse, struct hw_fib *aif_fib) { unsigned long mflags; dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); @@ -305,12 +306,14 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, kfree (fib); return 1; } - if (aif_fib != NULL) { + if (dev->sa_firmware) { + fib->hbacmd_size = index; /* store event type */ + } else if (aif_fib != NULL) { memcpy(hw_fib, aif_fib, sizeof(struct hw_fib)); } else { - memcpy(hw_fib, - (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + - index), sizeof(struct hw_fib)); + memcpy(hw_fib, (struct hw_fib *) + (((uintptr_t)(dev->regs.sa)) + index), + sizeof(struct hw_fib)); } INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; @@ -344,7 +347,7 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, (fib_callback)aac_aif_callback, fibctx); } else { struct fib *fib = &dev->fibs[index]; - struct hw_fib * hwfib = fib->hw_fib_va; + int start_callback = 0; /* * Remove this fib from the Outstanding I/O queue. @@ -362,60 +365,104 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, return 0; } - if (isFastResponse) { - /* - * Doctor the fib - */ - *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); - hwfib->header.XferState |= cpu_to_le32(AdapterProcessed); - fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; - } - FIB_COUNTER_INCREMENT(aac_config.FibRecved); - if (hwfib->header.Command == cpu_to_le16(NuFileSystem)) - { - __le32 *pstatus = (__le32 *)hwfib->data; - if (*pstatus & cpu_to_le32(0xffff0000)) - *pstatus = cpu_to_le32(ST_OK); - } - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) - { - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) - FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); - else - FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); - /* - * NOTE: we cannot touch the fib after this - * call, because it may have been deallocated. - */ - if (likely(fib->callback && fib->callback_data)) { - fib->flags &= FIB_CONTEXT_FLAG_FASTRESP; - fib->callback(fib->callback_data, fib); - } else - dev_info(&dev->pdev->dev, - "Invalid callback_fib[%d] (*%p)(%p)\n", - index, fib->callback, fib->callback_data); + if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) { + + if (isFastResponse) + fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; + + if (fib->callback) { + start_callback = 1; + } else { + unsigned long flagv; + int complete = 0; + + dprintk((KERN_INFO "event_wait up\n")); + spin_lock_irqsave(&fib->event_lock, flagv); + if (fib->done == 2) { + fib->done = 1; + complete = 1; + } else { + fib->done = 1; + up(&fib->event_wait); + } + spin_unlock_irqrestore(&fib->event_lock, flagv); + + spin_lock_irqsave(&dev->manage_lock, mflags); + dev->management_fib_count--; + spin_unlock_irqrestore(&dev->manage_lock, + mflags); + + FIB_COUNTER_INCREMENT(aac_config.NativeRecved); + if (complete) + aac_fib_complete(fib); + } } else { - unsigned long flagv; - dprintk((KERN_INFO "event_wait up\n")); - spin_lock_irqsave(&fib->event_lock, flagv); - if (!fib->done) { - fib->done = 1; - up(&fib->event_wait); + struct hw_fib *hwfib = fib->hw_fib_va; + + if (isFastResponse) { + /* Doctor the fib */ + *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); + hwfib->header.XferState |= + cpu_to_le32(AdapterProcessed); + fib->flags |= FIB_CONTEXT_FLAG_FASTRESP; } - spin_unlock_irqrestore(&fib->event_lock, flagv); - spin_lock_irqsave(&dev->manage_lock, mflags); - dev->management_fib_count--; - spin_unlock_irqrestore(&dev->manage_lock, mflags); + if (hwfib->header.Command == + cpu_to_le16(NuFileSystem)) { + __le32 *pstatus = (__le32 *)hwfib->data; - FIB_COUNTER_INCREMENT(aac_config.NormalRecved); - if (fib->done == 2) { + if (*pstatus & cpu_to_le32(0xffff0000)) + *pstatus = cpu_to_le32(ST_OK); + } + if (hwfib->header.XferState & + cpu_to_le32(NoResponseExpected | Async)) { + if (hwfib->header.XferState & cpu_to_le32( + NoResponseExpected)) + FIB_COUNTER_INCREMENT( + aac_config.NoResponseRecved); + else + FIB_COUNTER_INCREMENT( + aac_config.AsyncRecved); + start_callback = 1; + } else { + unsigned long flagv; + int complete = 0; + + dprintk((KERN_INFO "event_wait up\n")); spin_lock_irqsave(&fib->event_lock, flagv); - fib->done = 0; + if (fib->done == 2) { + fib->done = 1; + complete = 1; + } else { + fib->done = 1; + up(&fib->event_wait); + } spin_unlock_irqrestore(&fib->event_lock, flagv); + + spin_lock_irqsave(&dev->manage_lock, mflags); + dev->management_fib_count--; + spin_unlock_irqrestore(&dev->manage_lock, + mflags); + + FIB_COUNTER_INCREMENT(aac_config.NormalRecved); + if (complete) + aac_fib_complete(fib); + } + } + + + if (start_callback) { + /* + * NOTE: we cannot touch the fib after this + * call, because it may have been deallocated. + */ + if (likely(fib->callback && fib->callback_data)) { + fib->callback(fib->callback_data, fib); + } else { aac_fib_complete(fib); + aac_fib_free(fib); } } diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 3ecbf20ca29f..137d22d3a005 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,7 +58,7 @@ #include "aacraid.h" -#define AAC_DRIVER_VERSION "1.2-1" +#define AAC_DRIVER_VERSION "1.2.1" #ifndef AAC_DRIVER_BRANCH #define AAC_DRIVER_BRANCH "" #endif @@ -401,61 +402,89 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, static int aac_slave_configure(struct scsi_device *sdev) { struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; + int chn, tid; + unsigned int depth = 0; + unsigned int set_timeout = 0; + + chn = aac_logical_to_phys(sdev_channel(sdev)); + tid = sdev_id(sdev); + if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS && + aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW) { + depth = aac->hba_map[chn][tid].qd_limit; + set_timeout = 1; + goto common_config; + } + + if (aac->jbod && (sdev->type == TYPE_DISK)) sdev->removable = 1; - if ((sdev->type == TYPE_DISK) && - (sdev_channel(sdev) != CONTAINER_CHANNEL) && - (!aac->jbod || sdev->inq_periph_qual) && - (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) { + + if (sdev->type == TYPE_DISK + && sdev_channel(sdev) != CONTAINER_CHANNEL + && (!aac->jbod || sdev->inq_periph_qual) + && (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) { + if (expose_physicals == 0) return -ENXIO; + if (expose_physicals < 0) sdev->no_uld_attach = 1; } - if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && - (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) && - !sdev->no_uld_attach) { + + if (sdev->tagged_supported + && sdev->type == TYPE_DISK + && (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) + && !sdev->no_uld_attach) { + struct scsi_device * dev; struct Scsi_Host *host = sdev->host; unsigned num_lsu = 0; unsigned num_one = 0; - unsigned depth; unsigned cid; - /* - * Firmware has an individual device recovery time typically - * of 35 seconds, give us a margin. - */ - if (sdev->request_queue->rq_timeout < (45 * HZ)) - blk_queue_rq_timeout(sdev->request_queue, 45*HZ); + set_timeout = 1; + for (cid = 0; cid < aac->maximum_num_containers; ++cid) if (aac->fsa_dev[cid].valid) ++num_lsu; + __shost_for_each_device(dev, host) { - if (dev->tagged_supported && (dev->type == TYPE_DISK) && - (!aac->raid_scsi_mode || - (sdev_channel(sdev) != 2)) && - !dev->no_uld_attach) { + if (dev->tagged_supported + && dev->type == TYPE_DISK + && (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) + && !dev->no_uld_attach) { if ((sdev_channel(dev) != CONTAINER_CHANNEL) - || !aac->fsa_dev[sdev_id(dev)].valid) + || !aac->fsa_dev[sdev_id(dev)].valid) { ++num_lsu; - } else + } + } else { ++num_one; + } } + if (num_lsu == 0) ++num_lsu; - depth = (host->can_queue - num_one) / num_lsu; - if (depth > 256) - depth = 256; - else if (depth < 2) - depth = 2; - scsi_change_queue_depth(sdev, depth); - } else { - scsi_change_queue_depth(sdev, 1); - sdev->tagged_supported = 1; + depth = (host->can_queue - num_one) / num_lsu; } +common_config: + /* + * Firmware has an individual device recovery time typically + * of 35 seconds, give us a margin. + */ + if (set_timeout && sdev->request_queue->rq_timeout < (45 * HZ)) + blk_queue_rq_timeout(sdev->request_queue, 45*HZ); + + if (depth > 256) + depth = 256; + else if (depth < 1) + depth = 1; + + scsi_change_queue_depth(sdev, depth); + + sdev->tagged_supported = 1; + return 0; } @@ -470,6 +499,15 @@ static int aac_slave_configure(struct scsi_device *sdev) static int aac_change_queue_depth(struct scsi_device *sdev, int depth) { + struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata); + int chn, tid, is_native_device = 0; + + chn = aac_logical_to_phys(sdev_channel(sdev)); + tid = sdev_id(sdev); + if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS && + aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW) + is_native_device = 1; + if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && (sdev_channel(sdev) == CONTAINER_CHANNEL)) { struct scsi_device * dev; @@ -491,9 +529,12 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth) else if (depth < 2) depth = 2; return scsi_change_queue_depth(sdev, depth); + } else if (is_native_device) { + scsi_change_queue_depth(sdev, aac->hba_map[chn][tid].qd_limit); + } else { + scsi_change_queue_depth(sdev, 1); } - - return scsi_change_queue_depth(sdev, 1); + return sdev->queue_depth; } static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) @@ -516,8 +557,39 @@ static struct device_attribute aac_raid_level_attr = { .show = aac_show_raid_level }; +static ssize_t aac_show_unique_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata); + unsigned char sn[16]; + + memset(sn, 0, sizeof(sn)); + + if (sdev_channel(sdev) == CONTAINER_CHANNEL) + memcpy(sn, aac->fsa_dev[sdev_id(sdev)].identifier, sizeof(sn)); + + return snprintf(buf, 16 * 2 + 2, + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", + sn[0], sn[1], sn[2], sn[3], + sn[4], sn[5], sn[6], sn[7], + sn[8], sn[9], sn[10], sn[11], + sn[12], sn[13], sn[14], sn[15]); +} + +static struct device_attribute aac_unique_id_attr = { + .attr = { + .name = "unique_id", + .mode = 0444, + }, + .show = aac_show_unique_id +}; + + + static struct device_attribute *aac_dev_attrs[] = { &aac_raid_level_attr, + &aac_unique_id_attr, NULL, }; @@ -534,46 +606,136 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) struct scsi_device * dev = cmd->device; struct Scsi_Host * host = dev->host; struct aac_dev * aac = (struct aac_dev *)host->hostdata; - int count; + int count, found; + u32 bus, cid; int ret = FAILED; - printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%llu)\n", - AAC_DRIVERNAME, - host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun); - switch (cmd->cmnd[0]) { - case SERVICE_ACTION_IN_16: - if (!(aac->raw_io_interface) || - !(aac->raw_io_64) || - ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) - break; - case INQUIRY: - case READ_CAPACITY: - /* Mark associated FIB to not complete, eh handler does this */ + bus = aac_logical_to_phys(scmd_channel(cmd)); + cid = scmd_id(cmd); + if (aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { + struct fib *fib; + struct aac_hba_tm_req *tmf; + int status; + u64 address; + __le32 managed_request_id; + + pr_err("%s: Host adapter abort request (%d,%d,%d,%d)\n", + AAC_DRIVERNAME, + host->host_no, sdev_channel(dev), sdev_id(dev), (int)dev->lun); + + found = 0; for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->flags & FIB_CONTEXT_FLAG) && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; + fib = &aac->fibs[count]; + if (*(u8 *)fib->hw_fib_va != 0 && + (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) && + (fib->callback_data == cmd)) { + found = 1; + managed_request_id = ((struct aac_hba_cmd_req *) + fib->hw_fib_va)->request_id; + break; + } + } + if (!found) + return ret; + + /* start a HBA_TMF_ABORT_TASK TMF request */ + fib = aac_fib_alloc(aac); + if (!fib) + return ret; + + tmf = (struct aac_hba_tm_req *)fib->hw_fib_va; + memset(tmf, 0, sizeof(*tmf)); + tmf->tmf = HBA_TMF_ABORT_TASK; + tmf->it_nexus = aac->hba_map[bus][cid].rmw_nexus; + tmf->lun[1] = cmd->device->lun; + + address = (u64)fib->hw_error_pa; + tmf->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); + tmf->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff)); + tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + + fib->hbacmd_size = sizeof(*tmf); + cmd->SCp.sent_command = 0; + + status = aac_hba_send(HBA_IU_TYPE_SCSI_TM_REQ, fib, + (fib_callback) aac_hba_callback, + (void *) cmd); + + /* Wait up to 2 minutes for completion */ + for (count = 0; count < 120; ++count) { + if (cmd->SCp.sent_command) { ret = SUCCESS; + break; } + msleep(1000); } - break; - case TEST_UNIT_READY: - /* Mark associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct scsi_cmnd * command; - struct fib * fib = &aac->fibs[count]; - if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) && - (fib->flags & FIB_CONTEXT_FLAG) && - ((command = fib->callback_data)) && - (command->device == cmd->device)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - command->SCp.phase = AAC_OWNER_ERROR_HANDLER; - if (command == cmd) + + if (ret != SUCCESS) + pr_err("%s: Host adapter abort request timed out\n", + AAC_DRIVERNAME); + } else { + pr_err( + "%s: Host adapter abort request.\n" + "%s: Outstanding commands on (%d,%d,%d,%d):\n", + AAC_DRIVERNAME, AAC_DRIVERNAME, + host->host_no, sdev_channel(dev), sdev_id(dev), + (int)dev->lun); + switch (cmd->cmnd[0]) { + case SERVICE_ACTION_IN_16: + if (!(aac->raw_io_interface) || + !(aac->raw_io_64) || + ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) + break; + case INQUIRY: + case READ_CAPACITY: + /* + * Mark associated FIB to not complete, + * eh handler does this + */ + for (count = 0; + count < (host->can_queue + AAC_NUM_MGT_FIB); + ++count) { + struct fib *fib = &aac->fibs[count]; + + if (fib->hw_fib_va->header.XferState && + (fib->flags & FIB_CONTEXT_FLAG) && + (fib->callback_data == cmd)) { + fib->flags |= + FIB_CONTEXT_FLAG_TIMED_OUT; + cmd->SCp.phase = + AAC_OWNER_ERROR_HANDLER; ret = SUCCESS; + } + } + break; + case TEST_UNIT_READY: + /* + * Mark associated FIB to not complete, + * eh handler does this + */ + for (count = 0; + count < (host->can_queue + AAC_NUM_MGT_FIB); + ++count) { + struct scsi_cmnd *command; + struct fib *fib = &aac->fibs[count]; + + command = fib->callback_data; + + if ((fib->hw_fib_va->header.XferState & + cpu_to_le32 + (Async | NoResponseExpected)) && + (fib->flags & FIB_CONTEXT_FLAG) && + ((command)) && + (command->device == cmd->device)) { + fib->flags |= + FIB_CONTEXT_FLAG_TIMED_OUT; + command->SCp.phase = + AAC_OWNER_ERROR_HANDLER; + if (command == cmd) + ret = SUCCESS; + } } + break; } } return ret; @@ -588,70 +750,165 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) { struct scsi_device * dev = cmd->device; struct Scsi_Host * host = dev->host; - struct scsi_cmnd * command; - int count; struct aac_dev * aac = (struct aac_dev *)host->hostdata; - unsigned long flags; - - /* Mark the associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->flags & FIB_CONTEXT_FLAG) && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; + int count; + u32 bus, cid; + int ret = FAILED; + + bus = aac_logical_to_phys(scmd_channel(cmd)); + cid = scmd_id(cmd); + if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS && + aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { + struct fib *fib; + int status; + u64 address; + u8 command; + + pr_err("%s: Host adapter reset request. SCSI hang ?\n", + AAC_DRIVERNAME); + + fib = aac_fib_alloc(aac); + if (!fib) + return ret; + + + if (aac->hba_map[bus][cid].reset_state == 0) { + struct aac_hba_tm_req *tmf; + + /* start a HBA_TMF_LUN_RESET TMF request */ + tmf = (struct aac_hba_tm_req *)fib->hw_fib_va; + memset(tmf, 0, sizeof(*tmf)); + tmf->tmf = HBA_TMF_LUN_RESET; + tmf->it_nexus = aac->hba_map[bus][cid].rmw_nexus; + tmf->lun[1] = cmd->device->lun; + + address = (u64)fib->hw_error_pa; + tmf->error_ptr_hi = cpu_to_le32 + ((u32)(address >> 32)); + tmf->error_ptr_lo = cpu_to_le32 + ((u32)(address & 0xffffffff)); + tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + fib->hbacmd_size = sizeof(*tmf); + + command = HBA_IU_TYPE_SCSI_TM_REQ; + aac->hba_map[bus][cid].reset_state++; + } else if (aac->hba_map[bus][cid].reset_state >= 1) { + struct aac_hba_reset_req *rst; + + /* already tried, start a hard reset now */ + rst = (struct aac_hba_reset_req *)fib->hw_fib_va; + memset(rst, 0, sizeof(*rst)); + /* reset_type is already zero... */ + rst->it_nexus = aac->hba_map[bus][cid].rmw_nexus; + + address = (u64)fib->hw_error_pa; + rst->error_ptr_hi = cpu_to_le32((u32)(address >> 32)); + rst->error_ptr_lo = cpu_to_le32 + ((u32)(address & 0xffffffff)); + rst->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE); + fib->hbacmd_size = sizeof(*rst); + + command = HBA_IU_TYPE_SATA_REQ; + aac->hba_map[bus][cid].reset_state = 0; } - } - printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", - AAC_DRIVERNAME); + cmd->SCp.sent_command = 0; - if ((count = aac_check_health(aac))) - return count; - /* - * Wait for all commands to complete to this specific - * target (block maximum 60 seconds). - */ - for (count = 60; count; --count) { - int active = aac->in_reset; + status = aac_hba_send(command, fib, + (fib_callback) aac_hba_callback, + (void *) cmd); - if (active == 0) - __shost_for_each_device(dev, host) { - spin_lock_irqsave(&dev->list_lock, flags); - list_for_each_entry(command, &dev->cmd_list, list) { - if ((command != cmd) && - (command->SCp.phase == AAC_OWNER_FIRMWARE)) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flags); - if (active) + /* Wait up to 2 minutes for completion */ + for (count = 0; count < 120; ++count) { + if (cmd->SCp.sent_command) { + ret = SUCCESS; break; + } + msleep(1000); + } + if (ret != SUCCESS) + pr_err("%s: Host adapter reset request timed out\n", + AAC_DRIVERNAME); + } else { + struct scsi_cmnd *command; + unsigned long flags; + + /* Mark the assoc. FIB to not complete, eh handler does this */ + for (count = 0; + count < (host->can_queue + AAC_NUM_MGT_FIB); + ++count) { + struct fib *fib = &aac->fibs[count]; + + if (fib->hw_fib_va->header.XferState && + (fib->flags & FIB_CONTEXT_FLAG) && + (fib->callback_data == cmd)) { + fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; + cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; + } } + + pr_err("%s: Host adapter reset request. SCSI hang ?\n", + AAC_DRIVERNAME); + + count = aac_check_health(aac); + if (count) + return count; /* - * We can exit If all the commands are complete + * Wait for all commands to complete to this specific + * target (block maximum 60 seconds). */ - if (active == 0) - return SUCCESS; - ssleep(1); + for (count = 60; count; --count) { + int active = aac->in_reset; + + if (active == 0) + __shost_for_each_device(dev, host) { + spin_lock_irqsave(&dev->list_lock, flags); + list_for_each_entry(command, &dev->cmd_list, + list) { + if ((command != cmd) && + (command->SCp.phase == + AAC_OWNER_FIRMWARE)) { + active++; + break; + } + } + spin_unlock_irqrestore(&dev->list_lock, flags); + if (active) + break; + + } + /* + * We can exit If all the commands are complete + */ + if (active == 0) + return SUCCESS; + ssleep(1); + } + pr_err("%s: SCSI bus appears hung\n", AAC_DRIVERNAME); + + /* + * This adapter needs a blind reset, only do so for + * Adapters that support a register, instead of a commanded, + * reset. + */ + if (((aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_MU_RESET) || + (aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_DOORBELL_RESET)) && + aac_check_reset && + ((aac_check_reset != 1) || + !(aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_IGNORE_RESET))) { + /* Bypass wait for command quiesce */ + aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET); + } + ret = SUCCESS; } - printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); /* - * This adapter needs a blind reset, only do so for Adapters that - * support a register, instead of a commanded, reset. + * Cause an immediate retry of the command with a ten second delay + * after successful tur */ - if (((aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_MU_RESET) || - (aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_DOORBELL_RESET)) && - aac_check_reset && - ((aac_check_reset != 1) || - !(aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_IGNORE_RESET))) - aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ - return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ + return ret; } /** @@ -911,10 +1168,16 @@ static ssize_t aac_store_reset_adapter(struct device *device, const char *buf, size_t count) { int retval = -EACCES; + int bled = 0; + struct aac_dev *aac; + if (!capable(CAP_SYS_ADMIN)) return retval; - retval = aac_reset_adapter((struct aac_dev*)class_to_shost(device)->hostdata, buf[0] == '!'); + + aac = (struct aac_dev *)class_to_shost(device)->hostdata; + bled = buf[0] == '!' ? 1:0; + retval = aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET); if (retval >= 0) retval = count; return retval; @@ -1070,6 +1333,7 @@ static void __aac_shutdown(struct aac_dev * aac) { int i; + aac->adapter_shutdown = 1; aac_send_shutdown(aac); if (aac->aif_thread) { @@ -1285,7 +1549,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) else shost->this_id = shost->max_id; - if (aac_drivers[index].quirks & AAC_QUIRK_SRC) + if (!aac->sa_firmware && aac_drivers[index].quirks & AAC_QUIRK_SRC) aac_intr_normal(aac, 0, 2, 0, NULL); /* @@ -1327,35 +1591,12 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) static void aac_release_resources(struct aac_dev *aac) { - int i; - aac_adapter_disable_int(aac); - if (aac->pdev->device == PMC_DEVICE_S6 || - aac->pdev->device == PMC_DEVICE_S7 || - aac->pdev->device == PMC_DEVICE_S8 || - aac->pdev->device == PMC_DEVICE_S9) { - if (aac->max_msix > 1) { - for (i = 0; i < aac->max_msix; i++) - free_irq(pci_irq_vector(aac->pdev, i), - &(aac->aac_msix[i])); - } else { - free_irq(aac->pdev->irq, &(aac->aac_msix[0])); - } - } else { - free_irq(aac->pdev->irq, aac); - } - if (aac->msi) - pci_disable_msi(aac->pdev); - else if (aac->max_msix > 1) - pci_disable_msix(aac->pdev); - + aac_free_irq(aac); } static int aac_acquire_resources(struct aac_dev *dev) { - int i, j; - int instance = dev->id; - const char *name = dev->name; unsigned long status; /* * First clear out all interrupts. Then enable the one's that we @@ -1377,37 +1618,8 @@ static int aac_acquire_resources(struct aac_dev *dev) if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_ENABLE_MSIX); - if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { - for (i = 0; i < dev->max_msix; i++) { - dev->aac_msix[i].vector_no = i; - dev->aac_msix[i].dev = dev; - - if (request_irq(pci_irq_vector(dev->pdev, i), - dev->a_ops.adapter_intr, - 0, "aacraid", &(dev->aac_msix[i]))) { - printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", - name, instance, i); - for (j = 0 ; j < i ; j++) - free_irq(pci_irq_vector(dev->pdev, j), - &(dev->aac_msix[j])); - pci_disable_msix(dev->pdev); - goto error_iounmap; - } - } - } else { - dev->aac_msix[0].vector_no = 0; - dev->aac_msix[0].dev = dev; - - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED, "aacraid", - &(dev->aac_msix[0])) < 0) { - if (dev->msi) - pci_disable_msi(dev->pdev); - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - } + if (aac_acquire_irq(dev)) + goto error_iounmap; aac_adapter_enable_int(dev); @@ -1420,7 +1632,7 @@ static int aac_acquire_resources(struct aac_dev *dev) /* After EEH recovery or suspend resume, max_msix count * may change, therfore updating in init as well. */ - dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix); + dev->init->r7.no_of_msix_vectors = cpu_to_le32(dev->max_msix); aac_adapter_start(dev); } return 0; diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c index 6c53b1d8b2ba..c59074e782d6 100644 --- a/drivers/scsi/aacraid/nark.c +++ b/drivers/scsi/aacraid/nark.c @@ -5,7 +5,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 7d8013feedde..a1bc5bbf7a34 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,7 +61,7 @@ static int aac_rkt_select_comm(struct aac_dev *dev, int comm) * case warrants this half baked, but convenient, check here. */ if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) { - dev->init->MaxIoCommands = + dev->init->r7.max_io_commands = cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB); dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT; } diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index ac1638069335..0e69a80c3275 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -315,10 +316,10 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) static void aac_rx_start_adapter(struct aac_dev *dev) { - struct aac_init *init; + union aac_init *init; init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); + init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds()); // We can only use a 32 bit address here rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); @@ -470,7 +471,7 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size) return 0; } -static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) +static int aac_rx_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) { u32 var = 0; @@ -559,7 +560,7 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; dev->OIMR = status = rx_readb (dev, MUnit.OIMR); if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && - !aac_rx_restart_adapter(dev, 0)) + !aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) /* Make sure the Hardware FIFO is empty */ while ((++restart < 512) && (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); @@ -568,7 +569,8 @@ int _aac_rx_init(struct aac_dev *dev) */ status = rx_readl(dev, MUnit.OMRx[0]); if (status & KERNEL_PANIC) { - if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev))) + if (aac_rx_restart_adapter(dev, + aac_rx_check_health(dev), IOP_HWSOFT_RESET)) goto error_iounmap; ++restart; } @@ -606,7 +608,8 @@ int _aac_rx_init(struct aac_dev *dev) ((startup_timeout > 60) ? (startup_timeout - 60) : (startup_timeout / 2))))) { - if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))) + if (likely(!aac_rx_restart_adapter(dev, + aac_rx_check_health(dev), IOP_HWSOFT_RESET))) start = jiffies; ++restart; } diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 869aea23c041..553922fed524 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -245,19 +246,19 @@ static void aac_sa_interrupt_adapter (struct aac_dev *dev) static void aac_sa_start_adapter(struct aac_dev *dev) { - struct aac_init *init; + union aac_init *init; /* * Fill in the remaining pieces of the init. */ init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); + init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds()); /* We can only use a 32 bit address here */ sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } -static int aac_sa_restart_adapter(struct aac_dev *dev, int bled) +static int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) { return -EINVAL; } diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 0c453880f214..8e4e2ddbafd7 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -6,7 +6,8 @@ * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -135,8 +136,16 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id) if (mode & AAC_INT_MODE_AIF) { /* handle AIF */ - if (dev->aif_thread && dev->fsa_dev) - aac_intr_normal(dev, 0, 2, 0, NULL); + if (dev->sa_firmware) { + u32 events = src_readl(dev, MUnit.SCR0); + + aac_intr_normal(dev, events, 1, 0, NULL); + writel(events, &dev->IndexRegs->Mailbox[0]); + src_writel(dev, MUnit.IDR, 1 << 23); + } else { + if (dev->aif_thread && dev->fsa_dev) + aac_intr_normal(dev, 0, 2, 0, NULL); + } if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT); mode = 0; @@ -148,17 +157,19 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id) for (;;) { isFastResponse = 0; /* remove toggle bit (31) */ - handle = (dev->host_rrq[index] & 0x7fffffff); - /* check fast response bit (30) */ + handle = le32_to_cpu((dev->host_rrq[index]) + & 0x7fffffff); + /* check fast response bits (30, 1) */ if (handle & 0x40000000) isFastResponse = 1; handle &= 0x0000ffff; if (handle == 0) break; + handle >>= 2; if (dev->msi_enabled && dev->max_msix > 1) atomic_dec(&dev->rrq_outstanding[vector_no]); + aac_intr_normal(dev, handle, 0, isFastResponse, NULL); dev->host_rrq[index++] = 0; - aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL); if (index == (vector_no + 1) * dev->vector_cap) index = vector_no * dev->vector_cap; dev->host_rrq_idx[vector_no] = index; @@ -384,7 +395,7 @@ static void aac_src_notify_adapter(struct aac_dev *dev, u32 event) static void aac_src_start_adapter(struct aac_dev *dev) { - struct aac_init *init; + union aac_init *init; int i; /* reset host_rrq_idx first */ @@ -392,14 +403,26 @@ static void aac_src_start_adapter(struct aac_dev *dev) dev->host_rrq_idx[i] = i * dev->vector_cap; atomic_set(&dev->rrq_outstanding[i], 0); } + atomic_set(&dev->msix_counter, 0); dev->fibs_pushed_no = 0; init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { + init->r8.host_elapsed_seconds = cpu_to_le32(get_seconds()); + src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, + lower_32_bits(dev->init_pa), + upper_32_bits(dev->init_pa), + sizeof(struct _r8) + + (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq), + 0, 0, 0, NULL, NULL, NULL, NULL, NULL); + } else { + init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds()); + // We can only use a 32 bit address here + src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, + (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL); + } - /* We can only use a 32 bit address here */ - src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, - 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); } /** @@ -435,6 +458,11 @@ static int aac_src_check_health(struct aac_dev *dev) return 0; } +static inline u32 aac_get_vector(struct aac_dev *dev) +{ + return atomic_inc_return(&dev->msix_counter)%dev->max_msix; +} + /** * aac_src_deliver_message * @fib: fib to issue @@ -448,66 +476,125 @@ static int aac_src_deliver_message(struct fib *fib) u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; + int native_hba; #if !defined(writeq) unsigned long flags; #endif - u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size); u16 vector_no; atomic_inc(&q->numpending); - if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest && - dev->max_msix > 1) { - vector_no = fib->vector_no; - fib->hw_fib_va->header.Handle += (vector_no << 16); + native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0; + + + if (dev->msi_enabled && dev->max_msix > 1 && + (native_hba || fib->hw_fib_va->header.Command != AifRequest)) { + + if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) + && dev->sa_firmware) + vector_no = aac_get_vector(dev); + else + vector_no = fib->vector_no; + + if (native_hba) { + if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) { + struct aac_hba_tm_req *tm_req; + + tm_req = (struct aac_hba_tm_req *) + fib->hw_fib_va; + if (tm_req->iu_type == + HBA_IU_TYPE_SCSI_TM_REQ) { + ((struct aac_hba_tm_req *) + fib->hw_fib_va)->reply_qid + = vector_no; + ((struct aac_hba_tm_req *) + fib->hw_fib_va)->request_id + += (vector_no << 16); + } else { + ((struct aac_hba_reset_req *) + fib->hw_fib_va)->reply_qid + = vector_no; + ((struct aac_hba_reset_req *) + fib->hw_fib_va)->request_id + += (vector_no << 16); + } + } else { + ((struct aac_hba_cmd_req *) + fib->hw_fib_va)->reply_qid + = vector_no; + ((struct aac_hba_cmd_req *) + fib->hw_fib_va)->request_id + += (vector_no << 16); + } + } else { + fib->hw_fib_va->header.Handle += (vector_no << 16); + } } else { vector_no = 0; } atomic_inc(&dev->rrq_outstanding[vector_no]); - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { - /* Calculate the amount to the fibsize bits */ - fibsize = (hdr_size + 127) / 128 - 1; - if (fibsize > (ALIGN32 - 1)) - return -EMSGSIZE; - /* New FIB header, 32-bit */ + if (native_hba) { address = fib->hw_fib_pa; - fib->hw_fib_va->header.StructType = FIB_MAGIC2; - fib->hw_fib_va->header.SenderFibAddress = (u32)address; - fib->hw_fib_va->header.u.TimeStamp = 0; - BUG_ON(upper_32_bits(address) != 0L); + fibsize = (fib->hbacmd_size + 127) / 128 - 1; + if (fibsize > 31) + fibsize = 31; address |= fibsize; +#if defined(writeq) + src_writeq(dev, MUnit.IQN_L, (u64)address); +#else + spin_lock_irqsave(&fib->dev->iq_lock, flags); + src_writel(dev, MUnit.IQN_H, + upper_32_bits(address) & 0xffffffff); + src_writel(dev, MUnit.IQN_L, address & 0xffffffff); + spin_unlock_irqrestore(&fib->dev->iq_lock, flags); +#endif } else { - /* Calculate the amount to the fibsize bits */ - fibsize = (sizeof(struct aac_fib_xporthdr) + hdr_size + 127) / 128 - 1; - if (fibsize > (ALIGN32 - 1)) - return -EMSGSIZE; - - /* Fill XPORT header */ - pFibX = (void *)fib->hw_fib_va - sizeof(struct aac_fib_xporthdr); - pFibX->Handle = cpu_to_le32(fib->hw_fib_va->header.Handle); - pFibX->HostAddress = cpu_to_le64(fib->hw_fib_pa); - pFibX->Size = cpu_to_le32(hdr_size); - - /* - * The xport header has been 32-byte aligned for us so that fibsize - * can be masked out of this address by hardware. -- BenC - */ - address = fib->hw_fib_pa - sizeof(struct aac_fib_xporthdr); - if (address & (ALIGN32 - 1)) - return -EINVAL; + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || + dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { + /* Calculate the amount to the fibsize bits */ + fibsize = (le16_to_cpu(fib->hw_fib_va->header.Size) + + 127) / 128 - 1; + /* New FIB header, 32-bit */ + address = fib->hw_fib_pa; + fib->hw_fib_va->header.StructType = FIB_MAGIC2; + fib->hw_fib_va->header.SenderFibAddress = + cpu_to_le32((u32)address); + fib->hw_fib_va->header.u.TimeStamp = 0; + WARN_ON(upper_32_bits(address) != 0L); + } else { + /* Calculate the amount to the fibsize bits */ + fibsize = (sizeof(struct aac_fib_xporthdr) + + le16_to_cpu(fib->hw_fib_va->header.Size) + + 127) / 128 - 1; + /* Fill XPORT header */ + pFibX = (struct aac_fib_xporthdr *) + ((unsigned char *)fib->hw_fib_va - + sizeof(struct aac_fib_xporthdr)); + pFibX->Handle = fib->hw_fib_va->header.Handle; + pFibX->HostAddress = + cpu_to_le64((u64)fib->hw_fib_pa); + pFibX->Size = cpu_to_le32( + le16_to_cpu(fib->hw_fib_va->header.Size)); + address = fib->hw_fib_pa - + (u64)sizeof(struct aac_fib_xporthdr); + } + if (fibsize > 31) + fibsize = 31; address |= fibsize; - } + #if defined(writeq) - src_writeq(dev, MUnit.IQ_L, (u64)address); + src_writeq(dev, MUnit.IQ_L, (u64)address); #else - spin_lock_irqsave(&fib->dev->iq_lock, flags); - src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff); - src_writel(dev, MUnit.IQ_L, address & 0xffffffff); - spin_unlock_irqrestore(&fib->dev->iq_lock, flags); + spin_lock_irqsave(&fib->dev->iq_lock, flags); + src_writel(dev, MUnit.IQ_H, + upper_32_bits(address) & 0xffffffff); + src_writel(dev, MUnit.IQ_L, address & 0xffffffff); + spin_unlock_irqrestore(&fib->dev->iq_lock, flags); #endif + } return 0; } @@ -553,52 +640,117 @@ static int aac_srcv_ioremap(struct aac_dev *dev, u32 size) dev->base = dev->regs.src.bar0 = NULL; return 0; } + + dev->regs.src.bar1 = + ioremap(pci_resource_start(dev->pdev, 2), AAC_MIN_SRCV_BAR1_SIZE); + dev->base = NULL; + if (dev->regs.src.bar1 == NULL) + return -1; dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size); - if (dev->base == NULL) + if (dev->base == NULL) { + iounmap(dev->regs.src.bar1); + dev->regs.src.bar1 = NULL; return -1; + } dev->IndexRegs = &((struct src_registers __iomem *) dev->base)->u.denali.IndexRegs; return 0; } -static int aac_src_restart_adapter(struct aac_dev *dev, int bled) +static void aac_set_intx_mode(struct aac_dev *dev) +{ + if (dev->msi_enabled) { + aac_src_access_devreg(dev, AAC_ENABLE_INTX); + dev->msi_enabled = 0; + msleep(5000); /* Delay 5 seconds */ + } +} + +static void aac_send_iop_reset(struct aac_dev *dev, int bled) { u32 var, reset_mask; - if (bled >= 0) { - if (bled) - printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", + bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, + 0, 0, 0, 0, 0, 0, &var, + &reset_mask, NULL, NULL, NULL); + + if ((bled || var != 0x00000001) && !dev->doorbell_mask) + bled = -EINVAL; + else if (dev->doorbell_mask) { + reset_mask = dev->doorbell_mask; + bled = 0; + var = 0x00000001; + } + + aac_set_intx_mode(dev); + + if (!bled && (dev->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_DOORBELL_RESET)) { + src_writel(dev, MUnit.IDR, reset_mask); + } else { + src_writel(dev, MUnit.IDR, 0x100); + } + msleep(30000); +} + +static void aac_send_hardware_soft_reset(struct aac_dev *dev) +{ + u_int32_t val; + + val = readl(((char *)(dev->base) + IBW_SWR_OFFSET)); + val |= 0x01; + writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET)); + msleep_interruptible(20000); +} + +static int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) +{ + unsigned long status, start; + + if (bled < 0) + goto invalid_out; + + if (bled) + pr_err("%s%d: adapter kernel panic'd %x.\n", dev->name, dev->id, bled); - dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; - bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, - 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); - if ((bled || (var != 0x00000001)) && - !dev->doorbell_mask) - return -EINVAL; - else if (dev->doorbell_mask) { - reset_mask = dev->doorbell_mask; - bled = 0; - var = 0x00000001; - } - if ((dev->pdev->device == PMC_DEVICE_S7 || - dev->pdev->device == PMC_DEVICE_S8 || - dev->pdev->device == PMC_DEVICE_S9) && dev->msi_enabled) { - aac_src_access_devreg(dev, AAC_ENABLE_INTX); - dev->msi_enabled = 0; - msleep(5000); /* Delay 5 seconds */ - } + dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; - if (!bled && (dev->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_DOORBELL_RESET)) { - src_writel(dev, MUnit.IDR, reset_mask); - ssleep(45); - } else { - src_writel(dev, MUnit.IDR, 0x100); - ssleep(45); + switch (reset_type) { + case IOP_HWSOFT_RESET: + aac_send_iop_reset(dev, bled); + /* + * Check to see if KERNEL_UP_AND_RUNNING + * Wait for the adapter to be up and running. + * If !KERNEL_UP_AND_RUNNING issue HW Soft Reset + */ + status = src_readl(dev, MUnit.OMR); + if (dev->sa_firmware + && !(status & KERNEL_UP_AND_RUNNING)) { + start = jiffies; + do { + status = src_readl(dev, MUnit.OMR); + if (time_after(jiffies, + start+HZ*SOFT_RESET_TIME)) { + aac_send_hardware_soft_reset(dev); + start = jiffies; + } + } while (!(status & KERNEL_UP_AND_RUNNING)); } + break; + case HW_SOFT_RESET: + if (dev->sa_firmware) { + aac_send_hardware_soft_reset(dev); + aac_set_intx_mode(dev); + } + break; + default: + aac_send_iop_reset(dev, bled); + break; } +invalid_out: + if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) return -ENODEV; @@ -653,14 +805,15 @@ int aac_src_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; if ((aac_reset_devices || reset_devices) && - !aac_src_restart_adapter(dev, 0)) + !aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) ++restart; /* * Check to see if the board panic'd while booting. */ status = src_readl(dev, MUnit.OMR); if (status & KERNEL_PANIC) { - if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) + if (aac_src_restart_adapter(dev, + aac_src_check_health(dev), IOP_HWSOFT_RESET)) goto error_iounmap; ++restart; } @@ -701,7 +854,7 @@ int aac_src_init(struct aac_dev *dev) ? (startup_timeout - 60) : (startup_timeout / 2))))) { if (likely(!aac_src_restart_adapter(dev, - aac_src_check_health(dev)))) + aac_src_check_health(dev), IOP_HWSOFT_RESET))) start = jiffies; ++restart; } @@ -798,7 +951,7 @@ int aac_srcv_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; if ((aac_reset_devices || reset_devices) && - !aac_src_restart_adapter(dev, 0)) + !aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) ++restart; /* * Check to see if flash update is running. @@ -827,7 +980,8 @@ int aac_srcv_init(struct aac_dev *dev) */ status = src_readl(dev, MUnit.OMR); if (status & KERNEL_PANIC) { - if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) + if (aac_src_restart_adapter(dev, + aac_src_check_health(dev), IOP_HWSOFT_RESET)) goto error_iounmap; ++restart; } @@ -866,7 +1020,8 @@ int aac_srcv_init(struct aac_dev *dev) ((startup_timeout > 60) ? (startup_timeout - 60) : (startup_timeout / 2))))) { - if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev)))) + if (likely(!aac_src_restart_adapter(dev, + aac_src_check_health(dev), IOP_HWSOFT_RESET))) start = jiffies; ++restart; } @@ -897,7 +1052,8 @@ int aac_srcv_init(struct aac_dev *dev) if (aac_init_adapter(dev) == NULL) goto error_iounmap; - if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2) + if ((dev->comm_interface != AAC_COMM_MESSAGE_TYPE2) && + (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3)) goto error_iounmap; if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_ENABLE_MSIX); @@ -905,9 +1061,9 @@ int aac_srcv_init(struct aac_dev *dev) if (aac_acquire_irq(dev)) goto error_iounmap; - dev->dbg_base = dev->base_start; - dev->dbg_base_mapped = dev->base; - dev->dbg_size = dev->base_size; + dev->dbg_base = pci_resource_start(dev->pdev, 2); + dev->dbg_base_mapped = dev->regs.src.bar1; + dev->dbg_size = AAC_MIN_SRCV_BAR1_SIZE; dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; aac_adapter_enable_int(dev); |