diff options
Diffstat (limited to 'drivers/scsi/aacraid')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 473 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 54 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commctrl.c | 6 | ||||
-rw-r--r-- | drivers/scsi/aacraid/comminit.c | 49 | ||||
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 220 | ||||
-rw-r--r-- | drivers/scsi/aacraid/linit.c | 26 | ||||
-rw-r--r-- | drivers/scsi/aacraid/sa.c | 32 |
7 files changed, 564 insertions, 296 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index af3e4d3f9735..e7961cbd2c55 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -42,6 +42,8 @@ #include <linux/highmem.h> /* For flush_kernel_dcache_page */ #include <linux/module.h> +#include <asm/unaligned.h> + #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -913,8 +915,15 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex) memset(str, ' ', sizeof(*str)); if (sup_adap_info->adapter_type_text[0]) { - char *cp = sup_adap_info->adapter_type_text; int c; + char *cp; + char *cname = kmemdup(sup_adap_info->adapter_type_text, + sizeof(sup_adap_info->adapter_type_text), + GFP_ATOMIC); + if (!cname) + return; + + cp = cname; if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C')) inqstrcpy("SMC", str->vid); else { @@ -923,7 +932,7 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex) ++cp; c = *cp; *cp = '\0'; - inqstrcpy(sup_adap_info->adapter_type_text, str->vid); + inqstrcpy(cname, str->vid); *cp = c; while (*cp && *cp != ' ') ++cp; @@ -931,14 +940,11 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex) while (*cp == ' ') ++cp; /* last six chars reserved for vol type */ - c = 0; - if (strlen(cp) > sizeof(str->pid)) { - c = cp[sizeof(str->pid)]; + if (strlen(cp) > sizeof(str->pid)) cp[sizeof(str->pid)] = '\0'; - } inqstrcpy (cp, str->pid); - if (c) - cp[sizeof(str->pid)] = c; + + kfree(cname); } else { struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype); @@ -1660,87 +1666,309 @@ static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd) (void *) cmd); } -int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target) +static int aac_send_safw_bmic_cmd(struct aac_dev *dev, + struct aac_srb_unit *srbu, void *xfer_buf, int xfer_len) { - 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; - + struct fib *fibptr; + dma_addr_t addr; + int rcode; + int fibsize; + struct aac_srb *srb; + struct aac_srb_reply *srb_reply; + struct sgmap64 *sg64; + u32 vbus; + u32 vid; + + if (!dev->sa_firmware) + return 0; + /* allocate FIB */ fibptr = aac_fib_alloc(dev); if (!fibptr) - goto out; + return -ENOMEM; - fibsize = sizeof(struct aac_srb) - - sizeof(struct sgentry) + sizeof(struct sgentry64); - datasize = sizeof(struct aac_ciss_identify_pd); + aac_fib_init(fibptr); + fibptr->hw_fib_va->header.XferState &= + ~cpu_to_le32(FastResponseCapable); - identify_resp = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, - GFP_KERNEL); - if (!identify_resp) - goto fib_free_ptr; + fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + + sizeof(struct sgentry64); - vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.virt_device_bus); - vid = (u32)le16_to_cpu(dev->supplement_adapter_info.virt_device_target); + /* allocate DMA buffer for response */ + addr = dma_map_single(&dev->pdev->dev, xfer_buf, xfer_len, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(&dev->pdev->dev, addr)) { + rcode = -ENOMEM; + goto fib_error; + } - aac_fib_init(fibptr); + srb = fib_data(fibptr); + memcpy(srb, &srbu->srb, sizeof(struct aac_srb)); - 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); + vbus = (u32)le16_to_cpu( + dev->supplement_adapter_info.virt_device_bus); + vid = (u32)le16_to_cpu( + dev->supplement_adapter_info.virt_device_target); - 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; + /* set the common request fields */ + srb->channel = cpu_to_le32(vbus); + srb->id = cpu_to_le32(vid); + srb->lun = 0; + srb->function = cpu_to_le32(SRBF_ExecuteScsi); + srb->timeout = 0; + srb->retry_limit = 0; + srb->cdb_size = cpu_to_le32(16); + srb->count = cpu_to_le32(xfer_len); + + sg64 = (struct sgmap64 *)&srb->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(xfer_len); - 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); + /* + * Copy the updated data for other dumping or other usage if needed + */ + memcpy(&srbu->srb, srb, sizeof(struct aac_srb)); + + /* issue request to the controller */ + rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize, FsaNormal, + 1, 1, NULL, NULL); + + if (rcode == -ERESTARTSYS) + rcode = -ERESTART; + + if (unlikely(rcode < 0)) + goto bmic_error; + + srb_reply = (struct aac_srb_reply *)fib_data(fibptr); + memcpy(&srbu->srb_reply, srb_reply, sizeof(struct aac_srb_reply)); + +bmic_error: + dma_unmap_single(&dev->pdev->dev, addr, xfer_len, DMA_BIDIRECTIONAL); +fib_error: + aac_fib_complete(fibptr); + aac_fib_free(fibptr); + return rcode; +} + +static void aac_set_safw_target_qd(struct aac_dev *dev, int bus, int target) +{ + + struct aac_ciss_identify_pd *identify_resp; - rcode = aac_fib_send(ScsiPortCommand64, - fibptr, fibsize, FsaNormal, 1, 1, NULL, NULL); + if (dev->hba_map[bus][target].devtype != AAC_DEVTYPE_NATIVE_RAW) + return; + + identify_resp = dev->hba_map[bus][target].safw_identify_resp; + if (identify_resp == NULL) { + dev->hba_map[bus][target].qd_limit = 32; + return; + } if (identify_resp->current_queue_depth_limit <= 0 || - identify_resp->current_queue_depth_limit > 32) + identify_resp->current_queue_depth_limit > 255) dev->hba_map[bus][target].qd_limit = 32; else dev->hba_map[bus][target].qd_limit = identify_resp->current_queue_depth_limit; +} - dma_free_coherent(&dev->pdev->dev, datasize, identify_resp, addr); +static int aac_issue_safw_bmic_identify(struct aac_dev *dev, + struct aac_ciss_identify_pd **identify_resp, u32 bus, u32 target) +{ + int rcode = -ENOMEM; + int datasize; + struct aac_srb_unit srbu; + struct aac_srb *srbcmd; + struct aac_ciss_identify_pd *identify_reply; - aac_fib_complete(fibptr); + datasize = sizeof(struct aac_ciss_identify_pd); + identify_reply = kmalloc(datasize, GFP_KERNEL); + if (!identify_reply) + goto out; + + memset(&srbu, 0, sizeof(struct aac_srb_unit)); + + srbcmd = &srbu.srb; + srbcmd->flags = cpu_to_le32(SRB_DataIn); + srbcmd->cdb[0] = 0x26; + srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF); + srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE; + + rcode = aac_send_safw_bmic_cmd(dev, &srbu, identify_reply, datasize); + if (unlikely(rcode < 0)) + goto mem_free_all; + + *identify_resp = identify_reply; + +out: + return rcode; +mem_free_all: + kfree(identify_reply); + goto out; +} + +static inline void aac_free_safw_ciss_luns(struct aac_dev *dev) +{ + kfree(dev->safw_phys_luns); + dev->safw_phys_luns = NULL; +} + +/** + * aac_get_safw_ciss_luns() Process topology change + * @dev: aac_dev structure + * + * Execute a CISS REPORT PHYS LUNS and process the results into + * the current hba_map. + */ +static int aac_get_safw_ciss_luns(struct aac_dev *dev) +{ + int rcode = -ENOMEM; + int datasize; + struct aac_srb *srbcmd; + struct aac_srb_unit srbu; + struct aac_ciss_phys_luns_resp *phys_luns; + + datasize = sizeof(struct aac_ciss_phys_luns_resp) + + (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun); + phys_luns = kmalloc(datasize, GFP_KERNEL); + if (phys_luns == NULL) + goto out; + + memset(&srbu, 0, sizeof(struct aac_srb_unit)); + + srbcmd = &srbu.srb; + srbcmd->flags = cpu_to_le32(SRB_DataIn); + srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS; + srbcmd->cdb[1] = 2; /* extended reporting */ + srbcmd->cdb[8] = (u8)(datasize >> 8); + srbcmd->cdb[9] = (u8)(datasize); + + rcode = aac_send_safw_bmic_cmd(dev, &srbu, phys_luns, datasize); + if (unlikely(rcode < 0)) + goto mem_free_all; + + if (phys_luns->resp_flag != 2) { + rcode = -ENOMSG; + goto mem_free_all; + } + + dev->safw_phys_luns = phys_luns; + +out: + return rcode; +mem_free_all: + kfree(phys_luns); + goto out; +} + +static inline u32 aac_get_safw_phys_lun_count(struct aac_dev *dev) +{ + return get_unaligned_be32(&dev->safw_phys_luns->list_length[0])/24; +} + +static inline u32 aac_get_safw_phys_bus(struct aac_dev *dev, int lun) +{ + return dev->safw_phys_luns->lun[lun].level2[1] & 0x3f; +} + +static inline u32 aac_get_safw_phys_target(struct aac_dev *dev, int lun) +{ + return dev->safw_phys_luns->lun[lun].level2[0]; +} + +static inline u32 aac_get_safw_phys_expose_flag(struct aac_dev *dev, int lun) +{ + return dev->safw_phys_luns->lun[lun].bus >> 6; +} + +static inline u32 aac_get_safw_phys_attribs(struct aac_dev *dev, int lun) +{ + return dev->safw_phys_luns->lun[lun].node_ident[9]; +} + +static inline u32 aac_get_safw_phys_nexus(struct aac_dev *dev, int lun) +{ + return *((u32 *)&dev->safw_phys_luns->lun[lun].node_ident[12]); +} + +static inline u32 aac_get_safw_phys_device_type(struct aac_dev *dev, int lun) +{ + return dev->safw_phys_luns->lun[lun].node_ident[8]; +} + +static inline void aac_free_safw_identify_resp(struct aac_dev *dev, + int bus, int target) +{ + kfree(dev->hba_map[bus][target].safw_identify_resp); + dev->hba_map[bus][target].safw_identify_resp = NULL; +} + +static inline void aac_free_safw_all_identify_resp(struct aac_dev *dev, + int lun_count) +{ + int luns; + int i; + u32 bus; + u32 target; + + luns = aac_get_safw_phys_lun_count(dev); + + if (luns < lun_count) + lun_count = luns; + else if (lun_count < 0) + lun_count = luns; + + for (i = 0; i < lun_count; i++) { + bus = aac_get_safw_phys_bus(dev, i); + target = aac_get_safw_phys_target(dev, i); + + aac_free_safw_identify_resp(dev, bus, target); + } +} + +static int aac_get_safw_attr_all_targets(struct aac_dev *dev) +{ + int i; + int rcode = 0; + u32 lun_count; + u32 bus; + u32 target; + struct aac_ciss_identify_pd *identify_resp = NULL; + + lun_count = aac_get_safw_phys_lun_count(dev); + + for (i = 0; i < lun_count; ++i) { + + bus = aac_get_safw_phys_bus(dev, i); + target = aac_get_safw_phys_target(dev, i); + + rcode = aac_issue_safw_bmic_identify(dev, + &identify_resp, bus, target); + + if (unlikely(rcode < 0)) + goto free_identify_resp; + + dev->hba_map[bus][target].safw_identify_resp = identify_resp; + } -fib_free_ptr: - aac_fib_free(fibptr); out: return rcode; +free_identify_resp: + aac_free_safw_all_identify_resp(dev, i); + goto out; } /** - * aac_update hba_map()- update current hba map with data from FW + * aac_set_safw_attr_all_targets- update current hba map with data from FW * @dev: aac_dev structure * @phys_luns: FW information from report phys luns + * @rescan: Indicates scan type * * 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) +static void aac_set_safw_attr_all_targets(struct aac_dev *dev) { /* ok and extended reporting */ u32 lun_count, nexus; @@ -1748,24 +1976,21 @@ void aac_update_hba_map(struct aac_dev *dev, 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; + lun_count = aac_get_safw_phys_lun_count(dev); + + dev->scan_counter++; 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]); + bus = aac_get_safw_phys_bus(dev, i); + target = aac_get_safw_phys_target(dev, i); + expose_flag = aac_get_safw_phys_expose_flag(dev, i); + attribs = aac_get_safw_phys_attribs(dev, i); + nexus = aac_get_safw_phys_nexus(dev, i); 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; @@ -1778,95 +2003,45 @@ void aac_update_hba_map(struct aac_dev *dev, } else devtype = AAC_DEVTYPE_ARC_RAW; - if (devtype != AAC_DEVTYPE_NATIVE_RAW) - goto update_devtype; + dev->hba_map[bus][target].scan_counter = dev->scan_counter; - if (aac_issue_bmic_identify(dev, bus, target) < 0) - dev->hba_map[bus][target].qd_limit = 32; + aac_set_safw_target_qd(dev, bus, target); update_devtype: - if (rescan == AAC_INIT) - dev->hba_map[bus][target].devtype = devtype; - else - dev->hba_map[bus][target].new_devtype = 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 rescan) +static int aac_setup_safw_targets(struct aac_dev *dev) { - 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 = dma_alloc_coherent(&dev->pdev->dev, datasize, &addr, - GFP_KERNEL); - if (phys_luns == NULL) { - rcode = -ENOMEM; - goto err_out; - } - - vbus = (u32) le16_to_cpu( - dev->supplement_adapter_info.virt_device_bus); - vid = (u32) le16_to_cpu( - dev->supplement_adapter_info.virt_device_target); + rcode = aac_get_containers(dev); + if (unlikely(rcode < 0)) + goto out; - aac_fib_init(fibptr); + rcode = aac_get_safw_ciss_luns(dev); + if (unlikely(rcode < 0)) + goto out; - 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); + rcode = aac_get_safw_attr_all_targets(dev); + if (unlikely(rcode < 0)) + goto free_ciss_luns; - 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); - } + aac_set_safw_attr_all_targets(dev); - dma_free_coherent(&dev->pdev->dev, datasize, phys_luns, addr); -err_out: + aac_free_safw_all_identify_resp(dev, -1); +free_ciss_luns: + aac_free_safw_ciss_luns(dev); +out: return rcode; } +int aac_setup_safw_adapter(struct aac_dev *dev) +{ + return aac_setup_safw_targets(dev); +} + int aac_get_adapter_info(struct aac_dev* dev) { struct fib* fibptr; @@ -1969,12 +2144,6 @@ 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.virt_device_bus != 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); @@ -2739,14 +2908,6 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) } } else { /* check for physical non-dasd devices */ 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 diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index d52265416da2..0095fcbd1c88 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -41,6 +41,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> +#include <scsi/scsi_host.h> /*------------------------------------------------------------------------------ * D E F I N E S @@ -97,7 +98,7 @@ enum { #define PMC_GLOBAL_INT_BIT0 0x00000001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 50834 +# define AAC_DRIVER_BUILD 50877 # define AAC_DRIVER_BRANCH "-custom" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -117,9 +118,13 @@ enum { /* Thor: 5 phys. buses: #0: empty, 1-4: 256 targets each */ #define AAC_MAX_BUSES 5 #define AAC_MAX_TARGETS 256 +#define AAC_BUS_TARGET_LOOP (AAC_MAX_BUSES * AAC_MAX_TARGETS) #define AAC_MAX_NATIVE_SIZE 2048 #define FW_ERROR_BUFFER_SIZE 512 +#define get_bus_number(x) (x/AAC_MAX_TARGETS) +#define get_target_number(x) (x%AAC_MAX_TARGETS) + /* Thor AIF events */ #define SA_AIF_HOTPLUG (1<<1) #define SA_AIF_HARDWARE (1<<2) @@ -1334,17 +1339,17 @@ struct 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 + +#define AAC_SAFW_RESCAN_DELAY (10 * HZ) 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*/ + u32 scan_counter; + struct aac_ciss_identify_pd *safw_identify_resp; }; /* @@ -1560,6 +1565,7 @@ struct aac_dev spinlock_t fib_lock; struct mutex ioctl_mutex; + struct mutex scan_mutex; struct aac_queue_block *queues; /* * The user API will use an IOCTL to register itself to receive @@ -1605,6 +1611,7 @@ struct aac_dev int maximum_num_channels; struct fsa_dev_info *fsa_dev; struct task_struct *thread; + struct delayed_work safw_rescan_work; int cardtype; /* *This lock will protect the two 32-bit @@ -1668,9 +1675,11 @@ struct aac_dev u32 vector_cap; /* MSI-X vector capab.*/ int msi_enabled; /* MSI/MSI-X enabled */ atomic_t msix_counter; + u32 scan_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]; + struct aac_ciss_phys_luns_resp *safw_phys_luns; u8 adapter_shutdown; u32 handle_pci_error; bool init_reset; @@ -2023,6 +2032,12 @@ struct aac_srb_reply __le32 sense_data_size; u8 sense_data[AAC_SENSE_BUFFERSIZE]; // Can this be SCSI_SENSE_BUFFERSIZE }; + +struct aac_srb_unit { + struct aac_srb srb; + struct aac_srb_reply srb_reply; +}; + /* * SRB Flags */ @@ -2627,16 +2642,41 @@ static inline int aac_adapter_check_health(struct aac_dev *dev) return (dev)->a_ops.adapter_check_health(dev); } + +int aac_scan_host(struct aac_dev *dev); + +static inline void aac_schedule_safw_scan_worker(struct aac_dev *dev) +{ + schedule_delayed_work(&dev->safw_rescan_work, AAC_SAFW_RESCAN_DELAY); +} + +static inline void aac_safw_rescan_worker(struct work_struct *work) +{ + struct aac_dev *dev = container_of(to_delayed_work(work), + struct aac_dev, safw_rescan_work); + + wait_event(dev->scsi_host_ptr->host_wait, + !scsi_host_in_recovery(dev->scsi_host_ptr)); + + aac_scan_host(dev); +} + +static inline void aac_cancel_safw_rescan_worker(struct aac_dev *dev) +{ + if (dev->sa_firmware) + cancel_delayed_work_sync(&dev->safw_rescan_work); +} + /* SCp.phase values */ #define AAC_OWNER_MIDLEVEL 0x101 #define AAC_OWNER_LOWLEVEL 0x102 #define AAC_OWNER_ERROR_HANDLER 0x103 #define AAC_OWNER_FIRMWARE 0x106 +void aac_safw_rescan_worker(struct work_struct *work); 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); +int aac_setup_safw_adapter(struct aac_dev *dev); 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); diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 9ab0fa959d83..a2b3430072c7 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -1052,9 +1052,13 @@ static int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg) if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop))) return -EFAULT; + dev->adapter_shutdown = 1; + + mutex_unlock(&dev->ioctl_mutex); retval = aac_reset_adapter(dev, 0, reset.reset_type); - return retval; + mutex_lock(&dev->ioctl_mutex); + return retval; } int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 1bc623ad3faf..0dc7b5a4fea2 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -42,6 +42,8 @@ #include <linux/completion.h> #include <linux/mm.h> #include <scsi/scsi_host.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_cmnd.h> #include "aacraid.h" @@ -284,6 +286,38 @@ static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, q->entries = qsize; } +static void aac_wait_for_io_completion(struct aac_dev *aac) +{ + unsigned long flagv = 0; + int i = 0; + + for (i = 60; i; --i) { + struct scsi_device *dev; + struct scsi_cmnd *command; + int active = 0; + + __shost_for_each_device(dev, aac->scsi_host_ptr) { + spin_lock_irqsave(&dev->list_lock, flagv); + list_for_each_entry(command, &dev->cmd_list, list) { + if (command->SCp.phase == AAC_OWNER_FIRMWARE) { + active++; + break; + } + } + spin_unlock_irqrestore(&dev->list_lock, flagv); + if (active) + break; + + } + /* + * We can exit If all the commands are complete + */ + if (active == 0) + break; + ssleep(1); + } +} + /** * aac_send_shutdown - shutdown an adapter * @dev: Adapter to shutdown @@ -295,12 +329,10 @@ int aac_send_shutdown(struct aac_dev * dev) { struct fib * fibctx; struct aac_close *cmd; - int status; + int status = 0; - fibctx = aac_fib_alloc(dev); - if (!fibctx) - return -ENOMEM; - aac_fib_init(fibctx); + if (aac_adapter_check_health(dev)) + return status; if (!dev->adapter_shutdown) { mutex_lock(&dev->ioctl_mutex); @@ -308,6 +340,13 @@ int aac_send_shutdown(struct aac_dev * dev) mutex_unlock(&dev->ioctl_mutex); } + aac_wait_for_io_completion(dev); + + fibctx = aac_fib_alloc(dev); + if (!fibctx) + return -ENOMEM; + aac_fib_init(fibctx); + cmd = (struct aac_close *) fib_data(fibctx); cmd->command = cpu_to_le32(VM_CloseAll); cmd->cid = cpu_to_le32(0xfffffffe); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 80a8cb26cdea..84858d5c8257 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -33,6 +33,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/crash_dump.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/pci.h> @@ -1629,28 +1630,28 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) command->scsi_done(command); } /* - * Any Device that was already marked offline needs to be cleaned up + * Any Device that was already marked offline needs to be marked + * running */ __shost_for_each_device(dev, host) { - if (!scsi_device_online(dev)) { - sdev_printk(KERN_INFO, dev, "Removing offline device\n"); - scsi_remove_device(dev); - scsi_device_put(dev); - } + if (!scsi_device_online(dev)) + scsi_device_set_state(dev, SDEV_RUNNING); } retval = 0; out: aac->in_reset = 0; scsi_unblock_requests(host); + /* * Issue bus rescan to catch any configuration that might have * occurred */ - if (!retval) { - dev_info(&aac->pdev->dev, "Issuing bus rescan\n"); - scsi_scan_host(host); + if (!retval && !is_kdump_kernel()) { + dev_info(&aac->pdev->dev, "Scheduling bus rescan\n"); + aac_schedule_safw_scan_worker(aac); } + if (jafo) { spin_lock_irq(host->host_lock); } @@ -1681,31 +1682,6 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) */ host = aac->scsi_host_ptr; scsi_block_requests(host); - if (forced < 2) for (retval = 60; retval; --retval) { - struct scsi_device * dev; - struct scsi_cmnd * command; - int active = 0; - - __shost_for_each_device(dev, host) { - spin_lock_irqsave(&dev->list_lock, flagv); - list_for_each_entry(command, &dev->cmd_list, list) { - if (command->SCp.phase == AAC_OWNER_FIRMWARE) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flagv); - if (active) - break; - - } - /* - * We can exit If all the commands are complete - */ - if (active == 0) - break; - ssleep(1); - } /* Quiesce build, flush cache, write through mode */ if (forced < 2) @@ -1874,42 +1850,124 @@ out: return BlinkLED; } +static inline int is_safw_raid_volume(struct aac_dev *aac, int bus, int target) +{ + return bus == CONTAINER_CHANNEL && target < aac->maximum_num_containers; +} + +static struct scsi_device *aac_lookup_safw_scsi_device(struct aac_dev *dev, + int bus, + int target) +{ + if (bus != CONTAINER_CHANNEL) + bus = aac_phys_to_logical(bus); + + return scsi_device_lookup(dev->scsi_host_ptr, bus, target, 0); +} + +static int aac_add_safw_device(struct aac_dev *dev, int bus, int target) +{ + if (bus != CONTAINER_CHANNEL) + bus = aac_phys_to_logical(bus); + + return scsi_add_device(dev->scsi_host_ptr, bus, target, 0); +} + +static void aac_put_safw_scsi_device(struct scsi_device *sdev) +{ + if (sdev) + scsi_device_put(sdev); +} -static void aac_resolve_luns(struct aac_dev *dev) +static void aac_remove_safw_device(struct aac_dev *dev, int bus, int target) { - 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++) { + sdev = aac_lookup_safw_scsi_device(dev, bus, target); + scsi_remove_device(sdev); + aac_put_safw_scsi_device(sdev); +} - if (bus == CONTAINER_CHANNEL) - channel = CONTAINER_CHANNEL; - else - channel = aac_phys_to_logical(bus); +static inline int aac_is_safw_scan_count_equal(struct aac_dev *dev, + int bus, int target) +{ + return dev->hba_map[bus][target].scan_counter == dev->scan_counter; +} - devtype = dev->hba_map[bus][target].devtype; - new_devtype = dev->hba_map[bus][target].new_devtype; +static int aac_is_safw_target_valid(struct aac_dev *dev, int bus, int target) +{ + if (is_safw_raid_volume(dev, bus, target)) + return dev->fsa_dev[target].valid; + else + return aac_is_safw_scan_count_equal(dev, bus, target); +} - sdev = scsi_device_lookup(dev->scsi_host_ptr, channel, - target, 0); +static int aac_is_safw_device_exposed(struct aac_dev *dev, int bus, int target) +{ + int is_exposed = 0; + struct scsi_device *sdev; - if (!sdev && new_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); + sdev = aac_lookup_safw_scsi_device(dev, bus, target); + if (sdev) + is_exposed = 1; + aac_put_safw_scsi_device(sdev); - if (sdev) - scsi_device_put(sdev); + return is_exposed; +} - dev->hba_map[bus][target].devtype = new_devtype; - } +static int aac_update_safw_host_devices(struct aac_dev *dev) +{ + int i; + int bus; + int target; + int is_exposed = 0; + int rcode = 0; + + rcode = aac_setup_safw_adapter(dev); + if (unlikely(rcode < 0)) { + goto out; } + + for (i = 0; i < AAC_BUS_TARGET_LOOP; i++) { + + bus = get_bus_number(i); + target = get_target_number(i); + + is_exposed = aac_is_safw_device_exposed(dev, bus, target); + + if (aac_is_safw_target_valid(dev, bus, target) && !is_exposed) + aac_add_safw_device(dev, bus, target); + else if (!aac_is_safw_target_valid(dev, bus, target) && + is_exposed) + aac_remove_safw_device(dev, bus, target); + } +out: + return rcode; +} + +static int aac_scan_safw_host(struct aac_dev *dev) +{ + int rcode = 0; + + rcode = aac_update_safw_host_devices(dev); + if (rcode) + aac_schedule_safw_scan_worker(dev); + + return rcode; +} + +int aac_scan_host(struct aac_dev *dev) +{ + int rcode = 0; + + mutex_lock(&dev->scan_mutex); + if (dev->sa_firmware) + rcode = aac_scan_safw_host(dev); + else + scsi_scan_host(dev->scsi_host_ptr); + mutex_unlock(&dev->scan_mutex); + + return rcode; } /** @@ -1922,10 +1980,8 @@ static void aac_resolve_luns(struct aac_dev *dev) */ static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr) { - int i, bus, target, container, rcode = 0; + int i; u32 events = 0; - struct fib *fib; - struct scsi_device *sdev; if (fibptr->hbacmd_size & SA_AIF_HOTPLUG) events = SA_AIF_HOTPLUG; @@ -1947,44 +2003,8 @@ static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr) 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); - } - } - } + aac_scan_host(dev); + break; case SA_AIF_BPSTAT_CHANGE: diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index d55332de08f9..b3b931ab77eb 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -683,6 +683,9 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) u32 bus, cid; int ret = FAILED; + if (aac_adapter_check_health(aac)) + return ret; + bus = aac_logical_to_phys(scmd_channel(cmd)); cid = scmd_id(cmd); if (aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) { @@ -690,7 +693,6 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) 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, @@ -703,8 +705,6 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) (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; } } @@ -1375,18 +1375,15 @@ 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; - aac = (struct aac_dev *)class_to_shost(device)->hostdata; - bled = buf[0] == '!' ? 1:0; - retval = aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET); + retval = aac_reset_adapter(shost_priv(class_to_shost(device)), + buf[0] == '!', IOP_HWSOFT_RESET); if (retval >= 0) retval = count; + return retval; } @@ -1689,6 +1686,9 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&aac->fib_lock); mutex_init(&aac->ioctl_mutex); + mutex_init(&aac->scan_mutex); + + INIT_DELAYED_WORK(&aac->safw_rescan_work, aac_safw_rescan_worker); /* * Map in the registers from the adapter. */ @@ -1792,7 +1792,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) error = scsi_add_host(shost, &pdev->dev); if (error) goto out_deinit; - scsi_scan_host(shost); + + aac_scan_host(aac); pci_enable_pcie_error_reporting(pdev); pci_save_state(pdev); @@ -1877,6 +1878,7 @@ static int aac_suspend(struct pci_dev *pdev, pm_message_t state) struct aac_dev *aac = (struct aac_dev *)shost->hostdata; scsi_block_requests(shost); + aac_cancel_safw_rescan_worker(aac); aac_send_shutdown(aac); aac_release_resources(aac); @@ -1935,6 +1937,7 @@ static void aac_remove_one(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + aac_cancel_safw_rescan_worker(aac); scsi_remove_host(shost); __aac_shutdown(aac); @@ -1992,6 +1995,7 @@ static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev, aac->handle_pci_error = 1; scsi_block_requests(aac->scsi_host_ptr); + aac_cancel_safw_rescan_worker(aac); aac_flush_ios(aac); aac_release_resources(aac); @@ -2076,7 +2080,7 @@ static void aac_pci_resume(struct pci_dev *pdev) if (sdev->sdev_state == SDEV_OFFLINE) sdev->sdev_state = SDEV_RUNNING; scsi_unblock_requests(aac->scsi_host_ptr); - scsi_scan_host(aac->scsi_host_ptr); + aac_scan_host(aac); pci_save_state(pdev); dev_err(&pdev->dev, "aacraid: PCI error - resume\n"); diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 553922fed524..882f40353b96 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -329,6 +329,22 @@ int aac_sa_init(struct aac_dev *dev) instance = dev->id; name = dev->name; + /* + * Fill in the function dispatch table. + */ + + dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; + dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; + dev->a_ops.adapter_notify = aac_sa_notify_adapter; + dev->a_ops.adapter_sync_cmd = sa_sync_cmd; + dev->a_ops.adapter_check_health = aac_sa_check_health; + dev->a_ops.adapter_restart = aac_sa_restart_adapter; + dev->a_ops.adapter_start = aac_sa_start_adapter; + dev->a_ops.adapter_intr = aac_sa_intr; + dev->a_ops.adapter_deliver = aac_rx_deliver_producer; + dev->a_ops.adapter_ioremap = aac_sa_ioremap; + if (aac_sa_ioremap(dev, dev->base_size)) { printk(KERN_WARNING "%s: unable to map adapter.\n", name); goto error_iounmap; @@ -363,22 +379,6 @@ int aac_sa_init(struct aac_dev *dev) } /* - * Fill in the function dispatch table. - */ - - dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; - dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; - dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; - dev->a_ops.adapter_notify = aac_sa_notify_adapter; - dev->a_ops.adapter_sync_cmd = sa_sync_cmd; - dev->a_ops.adapter_check_health = aac_sa_check_health; - dev->a_ops.adapter_restart = aac_sa_restart_adapter; - dev->a_ops.adapter_start = aac_sa_start_adapter; - dev->a_ops.adapter_intr = aac_sa_intr; - dev->a_ops.adapter_deliver = aac_rx_deliver_producer; - dev->a_ops.adapter_ioremap = aac_sa_ioremap; - - /* * First clear out all interrupts. Then enable the one's that * we can handle. */ |