Merge branch 'pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
[pandora-kernel.git] / drivers / net / ethernet / qlogic / qlcnic / qlcnic_main.c
index b447cc5..0bd1638 100644 (file)
@@ -2135,13 +2135,13 @@ qlcnic_map_tx_skb(struct pci_dev *pdev,
                frag = &skb_shinfo(skb)->frags[i];
                nf = &pbuf->frag_array[i+1];
 
-               map = pci_map_page(pdev, frag->page, frag->page_offset,
-                               frag->size, PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, map))
+               map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+                                      DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, map))
                        goto unwind;
 
                nf->dma = map;
-               nf->length = frag->size;
+               nf->length = skb_frag_size(frag);
        }
 
        return 0;
@@ -2221,7 +2221,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
 
                for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
-                       delta += skb_shinfo(skb)->frags[i].size;
+                       delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
 
                if (!__pskb_pull_tail(skb, delta))
                        goto drop_packet;
@@ -2840,8 +2840,15 @@ qlcnic_fwinit_work(struct work_struct *work)
                goto wait_npar;
        }
 
+       if (dev_state == QLCNIC_DEV_INITIALIZING ||
+           dev_state == QLCNIC_DEV_READY) {
+               dev_info(&adapter->pdev->dev, "Detected state change from "
+                               "DEV_NEED_RESET, skipping ack check\n");
+               goto skip_ack_check;
+       }
+
        if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
-               dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
+               dev_info(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
                                        adapter->reset_ack_timeo);
                goto skip_ack_check;
        }
@@ -2928,15 +2935,36 @@ qlcnic_detach_work(struct work_struct *work)
 
        status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
 
-       if (status & QLCNIC_RCODE_FATAL_ERROR)
+       if (status & QLCNIC_RCODE_FATAL_ERROR) {
+               dev_err(&adapter->pdev->dev,
+                       "Detaching the device: peg halt status1=0x%x\n",
+                                       status);
+
+               if (QLCNIC_FWERROR_CODE(status) == QLCNIC_FWERROR_FAN_FAILURE) {
+                       dev_err(&adapter->pdev->dev,
+                       "On board active cooling fan failed. "
+                               "Device has been halted.\n");
+                       dev_err(&adapter->pdev->dev,
+                               "Replace the adapter.\n");
+               }
+
                goto err_ret;
+       }
 
-       if (adapter->temp == QLCNIC_TEMP_PANIC)
+       if (adapter->temp == QLCNIC_TEMP_PANIC) {
+               dev_err(&adapter->pdev->dev, "Detaching the device: temp=%d\n",
+                       adapter->temp);
                goto err_ret;
+       }
+
        /* Dont ack if this instance is the reset owner */
        if (!(adapter->flags & QLCNIC_FW_RESET_OWNER)) {
-               if (qlcnic_set_drv_state(adapter, adapter->dev_state))
+               if (qlcnic_set_drv_state(adapter, adapter->dev_state)) {
+                       dev_err(&adapter->pdev->dev,
+                               "Failed to set driver state,"
+                                       "detaching the device.\n");
                        goto err_ret;
+               }
        }
 
        adapter->fw_wait_cnt = 0;
@@ -2946,8 +2974,6 @@ qlcnic_detach_work(struct work_struct *work)
        return;
 
 err_ret:
-       dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
-                       status, adapter->temp);
        netif_device_attach(netdev);
        qlcnic_clr_all_drv_state(adapter, 1);
 }
@@ -3068,7 +3094,7 @@ static int
 qlcnic_check_health(struct qlcnic_adapter *adapter)
 {
        u32 state = 0, heartbeat;
-       struct net_device *netdev = adapter->netdev;
+       u32 peg_status;
 
        if (qlcnic_check_temp(adapter))
                goto detach;
@@ -3108,8 +3134,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
        if (auto_fw_reset)
                clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 
-       dev_info(&netdev->dev, "firmware hang detected\n");
-       dev_info(&adapter->pdev->dev, "Dumping hw/fw registers\n"
+       dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+       dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
                        "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
                        "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
                        "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
@@ -3121,6 +3147,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
                        QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
+       peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+       if (LSW(MSB(peg_status)) == 0x67)
+               dev_err(&adapter->pdev->dev,
+                       "Firmware aborted with error code 0x00006700. "
+                               "Device is being reset.\n");
 detach:
        adapter->dev_state = (state == QLCNIC_DEV_NEED_QUISCENT) ? state :
                QLCNIC_DEV_NEED_RESET;
@@ -3446,6 +3477,107 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
        return err;
 }
 
+static int
+qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
+                       u8 *rate)
+{
+       *rate = LSB(beacon);
+       *state = MSB(beacon);
+
+       QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
+
+       if (!*state) {
+               *rate = __QLCNIC_MAX_LED_RATE;
+               return 0;
+       } else if (*state > __QLCNIC_MAX_LED_STATE)
+               return -EINVAL;
+
+       if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_store_beacon(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       int max_sds_rings = adapter->max_sds_rings;
+       u16 beacon;
+       u8 b_state, b_rate;
+       int err;
+
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               dev_warn(dev, "LED test not supported for non "
+                               "privilege function\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (len != sizeof(u16))
+               return QL_STATUS_INVALID_PARAM;
+
+       memcpy(&beacon, buf, sizeof(u16));
+       err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
+       if (err)
+               return err;
+
+       if (adapter->ahw->beacon_state == b_state)
+               return len;
+
+       rtnl_lock();
+
+       if (!adapter->ahw->beacon_state)
+               if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
+                       rtnl_unlock();
+                       return -EBUSY;
+               }
+
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+               err = -EIO;
+               goto out;
+       }
+
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
+               if (err)
+                       goto out;
+               set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
+       }
+
+       err = qlcnic_config_led(adapter, b_state, b_rate);
+
+       if (!err) {
+               err = len;
+               adapter->ahw->beacon_state = b_state;
+       }
+
+       if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
+               qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
+
+ out:
+       if (!adapter->ahw->beacon_state)
+               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+       rtnl_unlock();
+
+       return err;
+}
+
+static ssize_t
+qlcnic_show_beacon(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
+}
+
+static struct device_attribute dev_attr_beacon = {
+       .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_beacon,
+       .store = qlcnic_store_beacon,
+};
+
 static int
 qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
                loff_t offset, size_t size)
@@ -4143,6 +4275,8 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
                return;
        if (device_create_file(dev, &dev_attr_diag_mode))
                dev_info(dev, "failed to create diag_mode sysfs entry\n");
+       if (device_create_file(dev, &dev_attr_beacon))
+               dev_info(dev, "failed to create beacon sysfs entry");
        if (device_create_bin_file(dev, &bin_attr_crb))
                dev_info(dev, "failed to create crb sysfs entry\n");
        if (device_create_bin_file(dev, &bin_attr_mem))
@@ -4173,6 +4307,7 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
                return;
        device_remove_file(dev, &dev_attr_diag_mode);
+       device_remove_file(dev, &dev_attr_beacon);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
        device_remove_bin_file(dev, &bin_attr_pci_config);