include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / message / fusion / mptsas.c
index 20e0b44..7668712 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
@@ -72,6 +73,7 @@
  */
 #define MPTSAS_RAID_CHANNEL    1
 
+#define SAS_CONFIG_PAGE_TIMEOUT                30
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
@@ -324,7 +326,6 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
 {
        struct fw_event_work *fw_event, *next;
        struct mptsas_target_reset_event *target_reset_list, *n;
-       u8      flush_q;
        MPT_SCSI_HOST   *hd = shost_priv(ioc->sh);
 
        /* flush the target_reset_list */
@@ -344,15 +345,10 @@ mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
             !ioc->fw_event_q || in_interrupt())
                return;
 
-       flush_q = 0;
        list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
                if (cancel_delayed_work(&fw_event->work))
                        mptsas_free_fw_event(ioc, fw_event);
-               else
-                       flush_q = 1;
        }
-       if (flush_q)
-               flush_workqueue(ioc->fw_event_q);
 }
 
 
@@ -661,7 +657,7 @@ mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
        cfg.pageAddr = starget->id;
        cfg.cfghdr.hdr = &hdr;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        if (mpt_config(ioc, &cfg) != 0)
                goto out;
@@ -851,7 +847,13 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                port_details->num_phys--;
                port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
                memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
-               sas_port_delete_phy(port_details->port, phy_info->phy);
+               if (phy_info->phy) {
+                       devtprintk(ioc, dev_printk(KERN_DEBUG,
+                               &phy_info->phy->dev, MYIOC_s_FMT
+                               "delete phy %d, phy-obj (0x%p)\n", ioc->name,
+                               phy_info->phy_id, phy_info->phy));
+                       sas_port_delete_phy(port_details->port, phy_info->phy);
+               }
                phy_info->port_details = NULL;
        }
 
@@ -1074,6 +1076,19 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
        return 0;
 }
 
+static void
+mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
+{
+       scsi_device_set_state(sdev, SDEV_BLOCK);
+}
+
+static void
+mptsas_block_io_starget(struct scsi_target *starget)
+{
+       if (starget)
+               starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
+}
+
 /**
  * mptsas_target_reset_queue
  *
@@ -1097,10 +1112,11 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
        id = sas_event_data->TargetID;
        channel = sas_event_data->Bus;
 
-       if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
-               return;
-
-       vtarget->deleted = 1; /* block IO */
+       vtarget = mptsas_find_vtarget(ioc, channel, id);
+       if (vtarget) {
+               mptsas_block_io_starget(vtarget->starget);
+               vtarget->deleted = 1; /* block IO */
+       }
 
        target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
            GFP_ATOMIC);
@@ -1272,7 +1288,6 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                }
                mptsas_cleanup_fw_event_q(ioc);
                mptsas_queue_rescan(ioc);
-               mptsas_fw_event_on(ioc);
                break;
        default:
                break;
@@ -1318,7 +1333,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -1592,6 +1607,7 @@ mptsas_firmware_event_work(struct work_struct *work)
                mptsas_scan_sas_topology(ioc);
                ioc->in_rescan = 0;
                mptsas_free_fw_event(ioc, fw_event);
+               mptsas_fw_event_on(ioc);
                return;
        }
 
@@ -1867,7 +1883,8 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
        if (ioc->sas_discovery_quiesce_io)
                return SCSI_MLQUEUE_HOST_BUSY;
 
-//     scsi_print_command(SCpnt);
+       if (ioc->debug_level & MPT_DEBUG_SCSI)
+               scsi_print_command(SCpnt);
 
        return mptscsih_qcmd(SCpnt,done);
 }
@@ -1891,7 +1908,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .eh_bus_reset_handler           = mptscsih_bus_reset,
        .eh_host_reset_handler          = mptscsih_host_reset,
        .bios_param                     = mptscsih_bios_param,
-       .can_queue                      = MPT_FC_CAN_QUEUE,
+       .can_queue                      = MPT_SAS_CAN_QUEUE,
        .this_id                        = -1,
        .sg_tablesize                   = MPT_SCSI_SG_DEPTH,
        .max_sectors                    = 8192,
@@ -1926,7 +1943,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
        cfg.pageAddr = phy->identify.phy_identifier;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -2278,7 +2295,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        cfg.pageAddr = 0;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -2349,7 +2366,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
 
        cfg.cfghdr.ehdr = &hdr;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
        cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
        cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
        cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
@@ -2411,7 +2428,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
 
        cfg.cfghdr.ehdr = &hdr;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        /* Get Phy Pg 0 for each Phy. */
        cfg.physAddr = -1;
@@ -2479,7 +2496,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        cfg.physAddr = -1;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        memset(device_info, 0, sizeof(struct mptsas_devinfo));
        error = mpt_config(ioc, &cfg);
@@ -2554,7 +2571,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        memset(port_info, 0, sizeof(struct mptsas_portinfo));
        error = mpt_config(ioc, &cfg);
@@ -2635,7 +2652,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        cfg.pageAddr = form + form_specific;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
        cfg.dir = 0;    /* read */
-       cfg.timeout = 10;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        error = mpt_config(ioc, &cfg);
        if (error)
@@ -2685,6 +2702,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        return error;
 }
 
+struct rep_manu_request{
+       u8 smp_frame_type;
+       u8 function;
+       u8 reserved;
+       u8 request_length;
+};
+
+struct rep_manu_reply{
+       u8 smp_frame_type; /* 0x41 */
+       u8 function; /* 0x01 */
+       u8 function_result;
+       u8 response_length;
+       u16 expander_change_count;
+       u8 reserved0[2];
+       u8 sas_format:1;
+       u8 reserved1:7;
+       u8 reserved2[3];
+       u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
+       u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
+       u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
+       u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
+       u16 component_id;
+       u8 component_revision_id;
+       u8 reserved3;
+       u8 vendor_specific[8];
+};
+
+/**
+  * mptsas_exp_repmanufacture_info -
+  * @ioc: per adapter object
+  * @sas_address: expander sas address
+  * @edev: the sas_expander_device object
+  *
+  * Fills in the sas_expander_device object when SMP port is created.
+  *
+  * Returns 0 for success, non-zero for failure.
+  */
+static int
+mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
+       u64 sas_address, struct sas_expander_device *edev)
+{
+       MPT_FRAME_HDR *mf;
+       SmpPassthroughRequest_t *smpreq;
+       SmpPassthroughReply_t *smprep;
+       struct rep_manu_reply *manufacture_reply;
+       struct rep_manu_request *manufacture_request;
+       int ret;
+       int flagsLength;
+       unsigned long timeleft;
+       char *psge;
+       unsigned long flags;
+       void *data_out = NULL;
+       dma_addr_t data_out_dma = 0;
+       u32 sz;
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
+                       __func__, ioc->name);
+               return -EFAULT;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
+       if (ret)
+               goto out;
+
+       mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+       if (!mf) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       smpreq = (SmpPassthroughRequest_t *)mf;
+       memset(smpreq, 0, sizeof(*smpreq));
+
+       sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
+
+       data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
+       if (!data_out) {
+               printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
+                       __FILE__, __LINE__, __func__);
+               ret = -ENOMEM;
+               goto put_mf;
+       }
+
+       manufacture_request = data_out;
+       manufacture_request->smp_frame_type = 0x40;
+       manufacture_request->function = 1;
+       manufacture_request->reserved = 0;
+       manufacture_request->request_length = 0;
+
+       smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+       smpreq->PhysicalPort = 0xFF;
+       *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
+       smpreq->RequestDataLength = sizeof(struct rep_manu_request);
+
+       psge = (char *)
+               (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
+
+       flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+               MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+               MPI_SGE_FLAGS_HOST_TO_IOC |
+               MPI_SGE_FLAGS_END_OF_BUFFER;
+       flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+       flagsLength |= sizeof(struct rep_manu_request);
+
+       ioc->add_sge(psge, flagsLength, data_out_dma);
+       psge += ioc->SGE_size;
+
+       flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+               MPI_SGE_FLAGS_SYSTEM_ADDRESS |
+               MPI_SGE_FLAGS_IOC_TO_HOST |
+               MPI_SGE_FLAGS_END_OF_BUFFER;
+       flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
+       flagsLength |= sizeof(struct rep_manu_reply);
+       ioc->add_sge(psge, flagsLength, data_out_dma +
+       sizeof(struct rep_manu_request));
+
+       INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
+       mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+       timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
+       if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               mpt_free_msg_frame(ioc, mf);
+               mf = NULL;
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out_free;
+               if (!timeleft)
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+               goto out_free;
+       }
+
+       mf = NULL;
+
+       if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
+               u8 *tmp;
+
+       smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+       if (le16_to_cpu(smprep->ResponseDataLength) !=
+               sizeof(struct rep_manu_reply))
+                       goto out_free;
+
+       manufacture_reply = data_out + sizeof(struct rep_manu_request);
+       strncpy(edev->vendor_id, manufacture_reply->vendor_id,
+               SAS_EXPANDER_VENDOR_ID_LEN);
+       strncpy(edev->product_id, manufacture_reply->product_id,
+               SAS_EXPANDER_PRODUCT_ID_LEN);
+       strncpy(edev->product_rev, manufacture_reply->product_rev,
+               SAS_EXPANDER_PRODUCT_REV_LEN);
+       edev->level = manufacture_reply->sas_format;
+       if (manufacture_reply->sas_format) {
+               strncpy(edev->component_vendor_id,
+                       manufacture_reply->component_vendor_id,
+                               SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+               tmp = (u8 *)&manufacture_reply->component_id;
+               edev->component_id = tmp[0] << 8 | tmp[1];
+               edev->component_revision_id =
+                       manufacture_reply->component_revision_id;
+               }
+       } else {
+               printk(MYIOC_s_ERR_FMT
+                       "%s: smp passthru reply failed to be returned\n",
+                       ioc->name, __func__);
+               ret = -ENXIO;
+       }
+out_free:
+       if (data_out_dma)
+               pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
+put_mf:
+       if (mf)
+               mpt_free_msg_frame(ioc, mf);
+out_unlock:
+       CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
+       mutex_unlock(&ioc->sas_mgmt.mutex);
+out:
+       return ret;
+ }
+
 static void
 mptsas_parse_device_info(struct sas_identify *identify,
                struct mptsas_devinfo *device_info)
@@ -2966,6 +3164,11 @@ static int mptsas_probe_one_phy(struct device *dev,
                        goto out;
                }
                mptsas_set_rphy(ioc, phy_info, rphy);
+               if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
+                       identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
+                               mptsas_exp_repmanufacture_info(ioc,
+                                       identify.sas_address,
+                                       rphy_to_expander_device(rphy));
        }
 
  out:
@@ -3307,6 +3510,7 @@ mptsas_send_expander_event(struct fw_event_work *fw_event)
        expander_data = (MpiEventDataSasExpanderStatusChange_t *)
            fw_event->event_data;
        memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
+       sas_address = le64_to_cpu(sas_address);
        port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
 
        if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
@@ -3518,7 +3722,7 @@ retry_page:
                } else
                        mptsas_volume_delete(ioc, sas_info->fw.id);
        }
-       mutex_lock(&ioc->sas_device_info_mutex);
+       mutex_unlock(&ioc->sas_device_info_mutex);
 
        /* expanders */
        mutex_lock(&ioc->sas_topology_mutex);
@@ -3549,7 +3753,7 @@ retry_page:
                        goto redo_expander_scan;
                }
        }
-       mutex_lock(&ioc->sas_topology_mutex);
+       mutex_unlock(&ioc->sas_topology_mutex);
 }
 
 /**
@@ -4760,10 +4964,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        /* set 16 byte cdb's */
        sh->max_cmd_len = 16;
-
-       sh->max_id = ioc->pfacts[0].PortSCSIID;
+       sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
+       sh->max_id = -1;
        sh->max_lun = max_lun;
-
        sh->transportt = mptsas_transport_template;
 
        /* Required entry.
@@ -4821,25 +5024,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
                 ioc->name, ioc->ScsiLookup));
 
-       /* Clear the TM flags
-        */
-       hd->abortSCpnt = NULL;
-
-       /* Clear the pointer used to store
-        * single-threaded commands, i.e., those
-        * issued during a bus scan, dv and
-        * configuration pages.
-        */
-       hd->cmdPtr = NULL;
-
-       /* Initialize this SCSI Hosts' timers
-        * To use, set the timer expires field
-        * and add_timer
-        */
-       init_timer(&hd->timer);
-       hd->timer.data = (unsigned long) hd;
-       hd->timer.function = mptscsih_timer_expired;
-
        ioc->sas_data.ptClear = mpt_pt_clear;
 
        hd->last_queue_full = 0;