scsi: hisi_sas: add initialisation for v3 pci-based controller
[linux-2.6-microblaze.git] / drivers / scsi / hisi_sas / hisi_sas_v3_hw.c
1 /*
2  * Copyright (c) 2017 Hisilicon Limited.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  */
10
11 #include "hisi_sas.h"
12 #define DRV_NAME "hisi_sas_v3_hw"
13
14 static const struct hisi_sas_hw hisi_sas_v3_hw = {
15 };
16
17 static struct Scsi_Host *
18 hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
19 {
20         struct Scsi_Host *shost;
21         struct hisi_hba *hisi_hba;
22         struct device *dev = &pdev->dev;
23
24         shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
25         if (!shost)
26                 goto err_out;
27         hisi_hba = shost_priv(shost);
28
29         hisi_hba->hw = &hisi_sas_v3_hw;
30         hisi_hba->pci_dev = pdev;
31         hisi_hba->dev = dev;
32         hisi_hba->shost = shost;
33         SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
34
35         init_timer(&hisi_hba->timer);
36
37         if (hisi_sas_get_fw_info(hisi_hba) < 0)
38                 goto err_out;
39
40         if (hisi_sas_alloc(hisi_hba, shost)) {
41                 hisi_sas_free(hisi_hba);
42                 goto err_out;
43         }
44
45         return shost;
46 err_out:
47         dev_err(dev, "shost alloc failed\n");
48         return NULL;
49 }
50
51 static int
52 hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
53 {
54         struct Scsi_Host *shost;
55         struct hisi_hba *hisi_hba;
56         struct device *dev = &pdev->dev;
57         struct asd_sas_phy **arr_phy;
58         struct asd_sas_port **arr_port;
59         struct sas_ha_struct *sha;
60         int rc, phy_nr, port_nr, i;
61
62         rc = pci_enable_device(pdev);
63         if (rc)
64                 goto err_out;
65
66         pci_set_master(pdev);
67
68         rc = pci_request_regions(pdev, DRV_NAME);
69         if (rc)
70                 goto err_out_disable_device;
71
72         if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
73             (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) {
74                 if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) ||
75                    (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) {
76                         dev_err(dev, "No usable DMA addressing method\n");
77                         rc = -EIO;
78                         goto err_out_regions;
79                 }
80         }
81
82         shost = hisi_sas_shost_alloc_pci(pdev);
83         if (!shost) {
84                 rc = -ENOMEM;
85                 goto err_out_regions;
86         }
87
88         sha = SHOST_TO_SAS_HA(shost);
89         hisi_hba = shost_priv(shost);
90         dev_set_drvdata(dev, sha);
91
92         hisi_hba->regs = pcim_iomap(pdev, 5, 0);
93         if (!hisi_hba->regs) {
94                 dev_err(dev, "cannot map register.\n");
95                 rc = -ENOMEM;
96                 goto err_out_ha;
97         }
98
99         phy_nr = port_nr = hisi_hba->n_phy;
100
101         arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
102         arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
103         if (!arr_phy || !arr_port) {
104                 rc = -ENOMEM;
105                 goto err_out_ha;
106         }
107
108         sha->sas_phy = arr_phy;
109         sha->sas_port = arr_port;
110         sha->core.shost = shost;
111         sha->lldd_ha = hisi_hba;
112
113         shost->transportt = hisi_sas_stt;
114         shost->max_id = HISI_SAS_MAX_DEVICES;
115         shost->max_lun = ~0;
116         shost->max_channel = 1;
117         shost->max_cmd_len = 16;
118         shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
119         shost->can_queue = hisi_hba->hw->max_command_entries;
120         shost->cmd_per_lun = hisi_hba->hw->max_command_entries;
121
122         sha->sas_ha_name = DRV_NAME;
123         sha->dev = dev;
124         sha->lldd_module = THIS_MODULE;
125         sha->sas_addr = &hisi_hba->sas_addr[0];
126         sha->num_phys = hisi_hba->n_phy;
127         sha->core.shost = hisi_hba->shost;
128
129         for (i = 0; i < hisi_hba->n_phy; i++) {
130                 sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
131                 sha->sas_port[i] = &hisi_hba->port[i].sas_port;
132         }
133
134         hisi_sas_init_add(hisi_hba);
135
136         rc = scsi_add_host(shost, dev);
137         if (rc)
138                 goto err_out_ha;
139
140         rc = sas_register_ha(sha);
141         if (rc)
142                 goto err_out_register_ha;
143
144         rc = hisi_hba->hw->hw_init(hisi_hba);
145         if (rc)
146                 goto err_out_register_ha;
147
148         scsi_scan_host(shost);
149
150         return 0;
151
152 err_out_register_ha:
153         scsi_remove_host(shost);
154 err_out_ha:
155         kfree(shost);
156 err_out_regions:
157         pci_release_regions(pdev);
158 err_out_disable_device:
159         pci_disable_device(pdev);
160 err_out:
161         return rc;
162 }
163
164 static void hisi_sas_v3_remove(struct pci_dev *pdev)
165 {
166         struct device *dev = &pdev->dev;
167         struct sas_ha_struct *sha = dev_get_drvdata(dev);
168         struct hisi_hba *hisi_hba = sha->lldd_ha;
169
170         sas_unregister_ha(sha);
171         sas_remove_host(sha->core.shost);
172
173         hisi_sas_free(hisi_hba);
174         pci_release_regions(pdev);
175         pci_disable_device(pdev);
176 }
177
178 enum {
179         /* instances of the controller */
180         hip08,
181 };
182
183 static const struct pci_device_id sas_v3_pci_table[] = {
184         { PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
185         {}
186 };
187
188 static struct pci_driver sas_v3_pci_driver = {
189         .name           = DRV_NAME,
190         .id_table       = sas_v3_pci_table,
191         .probe          = hisi_sas_v3_probe,
192         .remove         = hisi_sas_v3_remove,
193 };
194
195 module_pci_driver(sas_v3_pci_driver);
196
197 MODULE_VERSION(DRV_VERSION);
198 MODULE_LICENSE("GPL");
199 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
200 MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");
201 MODULE_ALIAS("platform:" DRV_NAME);