diff options
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 144 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 60 |
2 files changed, 202 insertions, 2 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 2ad7aeacd092..bd5c80f1b76d 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1509,11 +1509,141 @@ static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) return aac_scsi_32(fib, cmd); } +/** + * 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) +{ + /* 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; + +update_devtype: + dev->hba_map[bus][target].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 fibsize, datasize; + struct aac_ciss_phys_luns_resp *phys_luns; + struct aac_srb *srbcmd; + struct sgmap64 *sg64; + dma_addr_t addr; + u32 vbus, vid; + u32 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); + } + + 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; @@ -1544,6 +1674,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; @@ -1571,6 +1702,11 @@ 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; + } /* * GetBusInfo @@ -1603,6 +1739,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); + } + if (!dev->in_reset) { char buffer[16]; tmp = le32_to_cpu(dev->adapter_info.kernelrev); diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 1069c010f06f..00df610993a3 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -81,6 +81,27 @@ enum { #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 CISS_REPORT_PHYSICAL_LUNS 0xc3 + +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 */ @@ -993,6 +1014,20 @@ struct fib { dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ }; +#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 reset_state; /* 0 - no reset, 1..x - */ + /* after xth TM LUN reset */ + u8 expose; /*checks if to expose or not*/ +}; + /* * Adapter Information Block * @@ -1056,7 +1091,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) @@ -1287,6 +1343,7 @@ struct aac_dev u32 vector_cap; /* MSI-X vector capab.*/ int msi_enabled; /* MSI/MSI-X enabled */ 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; }; @@ -2171,6 +2228,7 @@ 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); 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); |