1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Marvell 88SE64xx/88SE94xx pci init |
4 | * |
5 | * Copyright 2007 Red Hat, Inc. |
6 | * Copyright 2008 Marvell. <kewei@marvell.com> |
7 | * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> |
8 | */ |
9 | |
10 | |
11 | #include "mv_sas.h" |
12 | |
13 | int interrupt_coalescing = 0x80; |
14 | |
15 | static struct scsi_transport_template *mvs_stt; |
16 | static const struct mvs_chip_info mvs_chips[] = { |
17 | [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, |
18 | [chip_6440] = { .n_host: 1, .n_phy: 4, .fis_offs: 0x400, .fis_count: 17, .srs_sz: 16, .sg_width: 6, .slot_width: 9, .dispatch: &mvs_64xx_dispatch, }, |
19 | [chip_6485] = { .n_host: 1, .n_phy: 8, .fis_offs: 0x800, .fis_count: 33, .srs_sz: 32, .sg_width: 6, .slot_width: 10, .dispatch: &mvs_64xx_dispatch, }, |
20 | [chip_9180] = { .n_host: 2, .n_phy: 4, .fis_offs: 0x800, .fis_count: 17, .srs_sz: 64, .sg_width: 8, .slot_width: 9, .dispatch: &mvs_94xx_dispatch, }, |
21 | [chip_9480] = { .n_host: 2, .n_phy: 4, .fis_offs: 0x800, .fis_count: 17, .srs_sz: 64, .sg_width: 8, .slot_width: 9, .dispatch: &mvs_94xx_dispatch, }, |
22 | [chip_9445] = { .n_host: 1, .n_phy: 4, .fis_offs: 0x800, .fis_count: 17, .srs_sz: 64, .sg_width: 8, .slot_width: 11, .dispatch: &mvs_94xx_dispatch, }, |
23 | [chip_9485] = { .n_host: 2, .n_phy: 4, .fis_offs: 0x800, .fis_count: 17, .srs_sz: 64, .sg_width: 8, .slot_width: 11, .dispatch: &mvs_94xx_dispatch, }, |
24 | [chip_1300] = { .n_host: 1, .n_phy: 4, .fis_offs: 0x400, .fis_count: 17, .srs_sz: 16, .sg_width: 6, .slot_width: 9, .dispatch: &mvs_64xx_dispatch, }, |
25 | [chip_1320] = { .n_host: 2, .n_phy: 4, .fis_offs: 0x800, .fis_count: 17, .srs_sz: 64, .sg_width: 8, .slot_width: 9, .dispatch: &mvs_94xx_dispatch, }, |
26 | }; |
27 | |
28 | static const struct attribute_group *mvst_host_groups[]; |
29 | |
30 | #define SOC_SAS_NUM 2 |
31 | |
32 | static const struct scsi_host_template mvs_sht = { |
33 | .module = THIS_MODULE, |
34 | .name = DRV_NAME, |
35 | .queuecommand = sas_queuecommand, |
36 | .dma_need_drain = ata_scsi_dma_need_drain, |
37 | .target_alloc = sas_target_alloc, |
38 | .slave_configure = sas_slave_configure, |
39 | .scan_finished = mvs_scan_finished, |
40 | .scan_start = mvs_scan_start, |
41 | .change_queue_depth = sas_change_queue_depth, |
42 | .bios_param = sas_bios_param, |
43 | .can_queue = 1, |
44 | .this_id = -1, |
45 | .sg_tablesize = SG_ALL, |
46 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, |
47 | .eh_device_reset_handler = sas_eh_device_reset_handler, |
48 | .eh_target_reset_handler = sas_eh_target_reset_handler, |
49 | .slave_alloc = sas_slave_alloc, |
50 | .target_destroy = sas_target_destroy, |
51 | .ioctl = sas_ioctl, |
52 | #ifdef CONFIG_COMPAT |
53 | .compat_ioctl = sas_ioctl, |
54 | #endif |
55 | .shost_groups = mvst_host_groups, |
56 | .track_queue_depth = 1, |
57 | }; |
58 | |
59 | static struct sas_domain_function_template mvs_transport_ops = { |
60 | .lldd_dev_found = mvs_dev_found, |
61 | .lldd_dev_gone = mvs_dev_gone, |
62 | .lldd_execute_task = mvs_queue_command, |
63 | .lldd_control_phy = mvs_phy_control, |
64 | |
65 | .lldd_abort_task = mvs_abort_task, |
66 | .lldd_abort_task_set = sas_abort_task_set, |
67 | .lldd_clear_task_set = sas_clear_task_set, |
68 | .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, |
69 | .lldd_lu_reset = mvs_lu_reset, |
70 | .lldd_query_task = mvs_query_task, |
71 | .lldd_port_formed = mvs_port_formed, |
72 | .lldd_port_deformed = mvs_port_deformed, |
73 | |
74 | .lldd_write_gpio = mvs_gpio_write, |
75 | |
76 | }; |
77 | |
78 | static void mvs_phy_init(struct mvs_info *mvi, int phy_id) |
79 | { |
80 | struct mvs_phy *phy = &mvi->phy[phy_id]; |
81 | struct asd_sas_phy *sas_phy = &phy->sas_phy; |
82 | |
83 | phy->mvi = mvi; |
84 | phy->port = NULL; |
85 | timer_setup(&phy->timer, NULL, 0); |
86 | sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; |
87 | sas_phy->iproto = SAS_PROTOCOL_ALL; |
88 | sas_phy->tproto = 0; |
89 | sas_phy->role = PHY_ROLE_INITIATOR; |
90 | sas_phy->oob_mode = OOB_NOT_CONNECTED; |
91 | sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; |
92 | |
93 | sas_phy->id = phy_id; |
94 | sas_phy->sas_addr = &mvi->sas_addr[0]; |
95 | sas_phy->frame_rcvd = &phy->frame_rcvd[0]; |
96 | sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata; |
97 | sas_phy->lldd_phy = phy; |
98 | } |
99 | |
100 | static void mvs_free(struct mvs_info *mvi) |
101 | { |
102 | struct mvs_wq *mwq; |
103 | int slot_nr; |
104 | |
105 | if (!mvi) |
106 | return; |
107 | |
108 | if (mvi->flags & MVF_FLAG_SOC) |
109 | slot_nr = MVS_SOC_SLOTS; |
110 | else |
111 | slot_nr = MVS_CHIP_SLOT_SZ; |
112 | |
113 | dma_pool_destroy(pool: mvi->dma_pool); |
114 | |
115 | if (mvi->tx) |
116 | dma_free_coherent(dev: mvi->dev, |
117 | size: sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, |
118 | cpu_addr: mvi->tx, dma_handle: mvi->tx_dma); |
119 | if (mvi->rx_fis) |
120 | dma_free_coherent(dev: mvi->dev, MVS_RX_FISL_SZ, |
121 | cpu_addr: mvi->rx_fis, dma_handle: mvi->rx_fis_dma); |
122 | if (mvi->rx) |
123 | dma_free_coherent(dev: mvi->dev, |
124 | size: sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), |
125 | cpu_addr: mvi->rx, dma_handle: mvi->rx_dma); |
126 | if (mvi->slot) |
127 | dma_free_coherent(dev: mvi->dev, |
128 | size: sizeof(*mvi->slot) * slot_nr, |
129 | cpu_addr: mvi->slot, dma_handle: mvi->slot_dma); |
130 | |
131 | if (mvi->bulk_buffer) |
132 | dma_free_coherent(dev: mvi->dev, TRASH_BUCKET_SIZE, |
133 | cpu_addr: mvi->bulk_buffer, dma_handle: mvi->bulk_buffer_dma); |
134 | if (mvi->bulk_buffer1) |
135 | dma_free_coherent(dev: mvi->dev, TRASH_BUCKET_SIZE, |
136 | cpu_addr: mvi->bulk_buffer1, dma_handle: mvi->bulk_buffer_dma1); |
137 | |
138 | MVS_CHIP_DISP->chip_iounmap(mvi); |
139 | if (mvi->shost) |
140 | scsi_host_put(t: mvi->shost); |
141 | list_for_each_entry(mwq, &mvi->wq_list, entry) |
142 | cancel_delayed_work(dwork: &mwq->work_q); |
143 | kfree(objp: mvi->rsvd_tags); |
144 | kfree(objp: mvi); |
145 | } |
146 | |
147 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
148 | static void mvs_tasklet(unsigned long opaque) |
149 | { |
150 | u32 stat; |
151 | u16 core_nr, i = 0; |
152 | |
153 | struct mvs_info *mvi; |
154 | struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque; |
155 | |
156 | core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; |
157 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; |
158 | |
159 | if (unlikely(!mvi)) |
160 | BUG_ON(1); |
161 | |
162 | stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq); |
163 | if (!stat) |
164 | goto out; |
165 | |
166 | for (i = 0; i < core_nr; i++) { |
167 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; |
168 | MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat); |
169 | } |
170 | out: |
171 | MVS_CHIP_DISP->interrupt_enable(mvi); |
172 | |
173 | } |
174 | #endif |
175 | |
176 | static irqreturn_t mvs_interrupt(int irq, void *opaque) |
177 | { |
178 | u32 stat; |
179 | struct mvs_info *mvi; |
180 | struct sas_ha_struct *sha = opaque; |
181 | #ifndef CONFIG_SCSI_MVSAS_TASKLET |
182 | u32 i; |
183 | u32 core_nr; |
184 | |
185 | core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; |
186 | #endif |
187 | |
188 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; |
189 | |
190 | if (unlikely(!mvi)) |
191 | return IRQ_NONE; |
192 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
193 | MVS_CHIP_DISP->interrupt_disable(mvi); |
194 | #endif |
195 | |
196 | stat = MVS_CHIP_DISP->isr_status(mvi, irq); |
197 | if (!stat) { |
198 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
199 | MVS_CHIP_DISP->interrupt_enable(mvi); |
200 | #endif |
201 | return IRQ_NONE; |
202 | } |
203 | |
204 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
205 | tasklet_schedule(t: &((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); |
206 | #else |
207 | for (i = 0; i < core_nr; i++) { |
208 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; |
209 | MVS_CHIP_DISP->isr(mvi, irq, stat); |
210 | } |
211 | #endif |
212 | return IRQ_HANDLED; |
213 | } |
214 | |
215 | static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) |
216 | { |
217 | int i = 0, slot_nr; |
218 | char pool_name[32]; |
219 | |
220 | if (mvi->flags & MVF_FLAG_SOC) |
221 | slot_nr = MVS_SOC_SLOTS; |
222 | else |
223 | slot_nr = MVS_CHIP_SLOT_SZ; |
224 | |
225 | spin_lock_init(&mvi->lock); |
226 | for (i = 0; i < mvi->chip->n_phy; i++) { |
227 | mvs_phy_init(mvi, phy_id: i); |
228 | mvi->port[i].wide_port_phymap = 0; |
229 | mvi->port[i].port_attached = 0; |
230 | INIT_LIST_HEAD(list: &mvi->port[i].list); |
231 | } |
232 | for (i = 0; i < MVS_MAX_DEVICES; i++) { |
233 | mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED; |
234 | mvi->devices[i].dev_type = SAS_PHY_UNUSED; |
235 | mvi->devices[i].device_id = i; |
236 | mvi->devices[i].dev_status = MVS_DEV_NORMAL; |
237 | } |
238 | |
239 | /* |
240 | * alloc and init our DMA areas |
241 | */ |
242 | mvi->tx = dma_alloc_coherent(dev: mvi->dev, |
243 | size: sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, |
244 | dma_handle: &mvi->tx_dma, GFP_KERNEL); |
245 | if (!mvi->tx) |
246 | goto err_out; |
247 | mvi->rx_fis = dma_alloc_coherent(dev: mvi->dev, MVS_RX_FISL_SZ, |
248 | dma_handle: &mvi->rx_fis_dma, GFP_KERNEL); |
249 | if (!mvi->rx_fis) |
250 | goto err_out; |
251 | |
252 | mvi->rx = dma_alloc_coherent(dev: mvi->dev, |
253 | size: sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), |
254 | dma_handle: &mvi->rx_dma, GFP_KERNEL); |
255 | if (!mvi->rx) |
256 | goto err_out; |
257 | mvi->rx[0] = cpu_to_le32(0xfff); |
258 | mvi->rx_cons = 0xfff; |
259 | |
260 | mvi->slot = dma_alloc_coherent(dev: mvi->dev, |
261 | size: sizeof(*mvi->slot) * slot_nr, |
262 | dma_handle: &mvi->slot_dma, GFP_KERNEL); |
263 | if (!mvi->slot) |
264 | goto err_out; |
265 | |
266 | mvi->bulk_buffer = dma_alloc_coherent(dev: mvi->dev, |
267 | TRASH_BUCKET_SIZE, |
268 | dma_handle: &mvi->bulk_buffer_dma, GFP_KERNEL); |
269 | if (!mvi->bulk_buffer) |
270 | goto err_out; |
271 | |
272 | mvi->bulk_buffer1 = dma_alloc_coherent(dev: mvi->dev, |
273 | TRASH_BUCKET_SIZE, |
274 | dma_handle: &mvi->bulk_buffer_dma1, GFP_KERNEL); |
275 | if (!mvi->bulk_buffer1) |
276 | goto err_out; |
277 | |
278 | sprintf(buf: pool_name, fmt: "%s%d" , "mvs_dma_pool" , mvi->id); |
279 | mvi->dma_pool = dma_pool_create(name: pool_name, dev: &mvi->pdev->dev, |
280 | size: MVS_SLOT_BUF_SZ, align: 16, allocation: 0); |
281 | if (!mvi->dma_pool) { |
282 | printk(KERN_DEBUG "failed to create dma pool %s.\n" , pool_name); |
283 | goto err_out; |
284 | } |
285 | |
286 | return 0; |
287 | err_out: |
288 | return 1; |
289 | } |
290 | |
291 | |
292 | int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex) |
293 | { |
294 | unsigned long res_start, res_len, res_flag_ex = 0; |
295 | struct pci_dev *pdev = mvi->pdev; |
296 | if (bar_ex != -1) { |
297 | /* |
298 | * ioremap main and peripheral registers |
299 | */ |
300 | res_start = pci_resource_start(pdev, bar_ex); |
301 | res_len = pci_resource_len(pdev, bar_ex); |
302 | if (!res_start || !res_len) |
303 | goto err_out; |
304 | |
305 | res_flag_ex = pci_resource_flags(pdev, bar_ex); |
306 | if (res_flag_ex & IORESOURCE_MEM) |
307 | mvi->regs_ex = ioremap(offset: res_start, size: res_len); |
308 | else |
309 | mvi->regs_ex = (void *)res_start; |
310 | if (!mvi->regs_ex) |
311 | goto err_out; |
312 | } |
313 | |
314 | res_start = pci_resource_start(pdev, bar); |
315 | res_len = pci_resource_len(pdev, bar); |
316 | if (!res_start || !res_len) { |
317 | iounmap(addr: mvi->regs_ex); |
318 | mvi->regs_ex = NULL; |
319 | goto err_out; |
320 | } |
321 | |
322 | mvi->regs = ioremap(offset: res_start, size: res_len); |
323 | |
324 | if (!mvi->regs) { |
325 | if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM)) |
326 | iounmap(addr: mvi->regs_ex); |
327 | mvi->regs_ex = NULL; |
328 | goto err_out; |
329 | } |
330 | |
331 | return 0; |
332 | err_out: |
333 | return -1; |
334 | } |
335 | |
336 | void mvs_iounmap(void __iomem *regs) |
337 | { |
338 | iounmap(addr: regs); |
339 | } |
340 | |
341 | static struct mvs_info *mvs_pci_alloc(struct pci_dev *pdev, |
342 | const struct pci_device_id *ent, |
343 | struct Scsi_Host *shost, unsigned int id) |
344 | { |
345 | struct mvs_info *mvi = NULL; |
346 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
347 | |
348 | mvi = kzalloc(size: sizeof(*mvi) + |
349 | (1L << mvs_chips[ent->driver_data].slot_width) * |
350 | sizeof(struct mvs_slot_info), GFP_KERNEL); |
351 | if (!mvi) |
352 | return NULL; |
353 | |
354 | mvi->pdev = pdev; |
355 | mvi->dev = &pdev->dev; |
356 | mvi->chip_id = ent->driver_data; |
357 | mvi->chip = &mvs_chips[mvi->chip_id]; |
358 | INIT_LIST_HEAD(list: &mvi->wq_list); |
359 | |
360 | ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi; |
361 | ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy; |
362 | |
363 | mvi->id = id; |
364 | mvi->sas = sha; |
365 | mvi->shost = shost; |
366 | |
367 | mvi->rsvd_tags = bitmap_zalloc(nbits: MVS_RSVD_SLOTS, GFP_KERNEL); |
368 | if (!mvi->rsvd_tags) |
369 | goto err_out; |
370 | |
371 | if (MVS_CHIP_DISP->chip_ioremap(mvi)) |
372 | goto err_out; |
373 | if (!mvs_alloc(mvi, shost)) |
374 | return mvi; |
375 | err_out: |
376 | mvs_free(mvi); |
377 | return NULL; |
378 | } |
379 | |
380 | static int pci_go_64(struct pci_dev *pdev) |
381 | { |
382 | int rc; |
383 | |
384 | rc = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
385 | if (rc) { |
386 | rc = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(32)); |
387 | if (rc) { |
388 | dev_printk(KERN_ERR, &pdev->dev, |
389 | "32-bit DMA enable failed\n" ); |
390 | return rc; |
391 | } |
392 | } |
393 | |
394 | return rc; |
395 | } |
396 | |
397 | static int mvs_prep_sas_ha_init(struct Scsi_Host *shost, |
398 | const struct mvs_chip_info *chip_info) |
399 | { |
400 | int phy_nr, port_nr; unsigned short core_nr; |
401 | struct asd_sas_phy **arr_phy; |
402 | struct asd_sas_port **arr_port; |
403 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
404 | |
405 | core_nr = chip_info->n_host; |
406 | phy_nr = core_nr * chip_info->n_phy; |
407 | port_nr = phy_nr; |
408 | |
409 | memset(sha, 0x00, sizeof(struct sas_ha_struct)); |
410 | arr_phy = kcalloc(n: phy_nr, size: sizeof(void *), GFP_KERNEL); |
411 | arr_port = kcalloc(n: port_nr, size: sizeof(void *), GFP_KERNEL); |
412 | if (!arr_phy || !arr_port) |
413 | goto exit_free; |
414 | |
415 | sha->sas_phy = arr_phy; |
416 | sha->sas_port = arr_port; |
417 | sha->shost = shost; |
418 | |
419 | sha->lldd_ha = kzalloc(size: sizeof(struct mvs_prv_info), GFP_KERNEL); |
420 | if (!sha->lldd_ha) |
421 | goto exit_free; |
422 | |
423 | ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; |
424 | |
425 | shost->transportt = mvs_stt; |
426 | shost->max_id = MVS_MAX_DEVICES; |
427 | shost->max_lun = ~0; |
428 | shost->max_channel = 1; |
429 | shost->max_cmd_len = 16; |
430 | |
431 | return 0; |
432 | exit_free: |
433 | kfree(objp: arr_phy); |
434 | kfree(objp: arr_port); |
435 | return -1; |
436 | |
437 | } |
438 | |
439 | static void mvs_post_sas_ha_init(struct Scsi_Host *shost, |
440 | const struct mvs_chip_info *chip_info) |
441 | { |
442 | int can_queue, i = 0, j = 0; |
443 | struct mvs_info *mvi = NULL; |
444 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
445 | unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; |
446 | |
447 | for (j = 0; j < nr_core; j++) { |
448 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; |
449 | for (i = 0; i < chip_info->n_phy; i++) { |
450 | sha->sas_phy[j * chip_info->n_phy + i] = |
451 | &mvi->phy[i].sas_phy; |
452 | sha->sas_port[j * chip_info->n_phy + i] = |
453 | &mvi->port[i].sas_port; |
454 | } |
455 | } |
456 | |
457 | sha->sas_ha_name = DRV_NAME; |
458 | sha->dev = mvi->dev; |
459 | sha->sas_addr = &mvi->sas_addr[0]; |
460 | |
461 | sha->num_phys = nr_core * chip_info->n_phy; |
462 | |
463 | if (mvi->flags & MVF_FLAG_SOC) |
464 | can_queue = MVS_SOC_CAN_QUEUE; |
465 | else |
466 | can_queue = MVS_CHIP_SLOT_SZ; |
467 | |
468 | can_queue -= MVS_RSVD_SLOTS; |
469 | |
470 | shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); |
471 | shost->can_queue = can_queue; |
472 | mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; |
473 | sha->shost = mvi->shost; |
474 | } |
475 | |
476 | static void mvs_init_sas_add(struct mvs_info *mvi) |
477 | { |
478 | u8 i; |
479 | for (i = 0; i < mvi->chip->n_phy; i++) { |
480 | mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; |
481 | mvi->phy[i].dev_sas_addr = |
482 | cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr)); |
483 | } |
484 | |
485 | memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE); |
486 | } |
487 | |
488 | static int mvs_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) |
489 | { |
490 | unsigned int rc, nhost = 0; |
491 | struct mvs_info *mvi; |
492 | irq_handler_t irq_handler = mvs_interrupt; |
493 | struct Scsi_Host *shost = NULL; |
494 | const struct mvs_chip_info *chip; |
495 | |
496 | dev_printk(KERN_INFO, &pdev->dev, |
497 | "mvsas: driver version %s\n" , DRV_VERSION); |
498 | rc = pci_enable_device(dev: pdev); |
499 | if (rc) |
500 | goto err_out_enable; |
501 | |
502 | pci_set_master(dev: pdev); |
503 | |
504 | rc = pci_request_regions(pdev, DRV_NAME); |
505 | if (rc) |
506 | goto err_out_disable; |
507 | |
508 | rc = pci_go_64(pdev); |
509 | if (rc) |
510 | goto err_out_regions; |
511 | |
512 | shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); |
513 | if (!shost) { |
514 | rc = -ENOMEM; |
515 | goto err_out_regions; |
516 | } |
517 | |
518 | chip = &mvs_chips[ent->driver_data]; |
519 | SHOST_TO_SAS_HA(shost) = |
520 | kcalloc(n: 1, size: sizeof(struct sas_ha_struct), GFP_KERNEL); |
521 | if (!SHOST_TO_SAS_HA(shost)) { |
522 | scsi_host_put(t: shost); |
523 | rc = -ENOMEM; |
524 | goto err_out_regions; |
525 | } |
526 | |
527 | rc = mvs_prep_sas_ha_init(shost, chip_info: chip); |
528 | if (rc) { |
529 | scsi_host_put(t: shost); |
530 | rc = -ENOMEM; |
531 | goto err_out_regions; |
532 | } |
533 | |
534 | pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); |
535 | |
536 | do { |
537 | mvi = mvs_pci_alloc(pdev, ent, shost, id: nhost); |
538 | if (!mvi) { |
539 | rc = -ENOMEM; |
540 | goto err_out_regions; |
541 | } |
542 | |
543 | memset(&mvi->hba_info_param, 0xFF, |
544 | sizeof(struct hba_info_page)); |
545 | |
546 | mvs_init_sas_add(mvi); |
547 | |
548 | mvi->instance = nhost; |
549 | rc = MVS_CHIP_DISP->chip_init(mvi); |
550 | if (rc) { |
551 | mvs_free(mvi); |
552 | goto err_out_regions; |
553 | } |
554 | nhost++; |
555 | } while (nhost < chip->n_host); |
556 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
557 | { |
558 | struct mvs_prv_info *mpi = SHOST_TO_SAS_HA(shost)->lldd_ha; |
559 | |
560 | tasklet_init(t: &(mpi->mv_tasklet), func: mvs_tasklet, |
561 | data: (unsigned long)SHOST_TO_SAS_HA(shost)); |
562 | } |
563 | #endif |
564 | |
565 | mvs_post_sas_ha_init(shost, chip_info: chip); |
566 | |
567 | rc = scsi_add_host(host: shost, dev: &pdev->dev); |
568 | if (rc) |
569 | goto err_out_shost; |
570 | |
571 | rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); |
572 | if (rc) |
573 | goto err_out_shost; |
574 | rc = request_irq(irq: pdev->irq, handler: irq_handler, IRQF_SHARED, |
575 | DRV_NAME, SHOST_TO_SAS_HA(shost)); |
576 | if (rc) |
577 | goto err_not_sas; |
578 | |
579 | MVS_CHIP_DISP->interrupt_enable(mvi); |
580 | |
581 | scsi_scan_host(mvi->shost); |
582 | |
583 | return 0; |
584 | |
585 | err_not_sas: |
586 | sas_unregister_ha(SHOST_TO_SAS_HA(shost)); |
587 | err_out_shost: |
588 | scsi_remove_host(mvi->shost); |
589 | err_out_regions: |
590 | pci_release_regions(pdev); |
591 | err_out_disable: |
592 | pci_disable_device(dev: pdev); |
593 | err_out_enable: |
594 | return rc; |
595 | } |
596 | |
597 | static void mvs_pci_remove(struct pci_dev *pdev) |
598 | { |
599 | unsigned short core_nr, i = 0; |
600 | struct sas_ha_struct *sha = pci_get_drvdata(pdev); |
601 | struct mvs_info *mvi = NULL; |
602 | |
603 | core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; |
604 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; |
605 | |
606 | #ifdef CONFIG_SCSI_MVSAS_TASKLET |
607 | tasklet_kill(t: &((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); |
608 | #endif |
609 | |
610 | sas_unregister_ha(sha); |
611 | sas_remove_host(mvi->shost); |
612 | |
613 | MVS_CHIP_DISP->interrupt_disable(mvi); |
614 | free_irq(mvi->pdev->irq, sha); |
615 | for (i = 0; i < core_nr; i++) { |
616 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; |
617 | mvs_free(mvi); |
618 | } |
619 | kfree(objp: sha->sas_phy); |
620 | kfree(objp: sha->sas_port); |
621 | kfree(objp: sha); |
622 | pci_release_regions(pdev); |
623 | pci_disable_device(dev: pdev); |
624 | return; |
625 | } |
626 | |
627 | static struct pci_device_id mvs_pci_table[] = { |
628 | { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, |
629 | { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, |
630 | { |
631 | .vendor = PCI_VENDOR_ID_MARVELL, |
632 | .device = 0x6440, |
633 | .subvendor = PCI_ANY_ID, |
634 | .subdevice = 0x6480, |
635 | .class = 0, |
636 | .class_mask = 0, |
637 | .driver_data = chip_6485, |
638 | }, |
639 | { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, |
640 | { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 }, |
641 | { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 }, |
642 | { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, |
643 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, |
644 | { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, |
645 | { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, |
646 | { PCI_VDEVICE(TTI, 0x2640), chip_6440 }, |
647 | { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, |
648 | { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, |
649 | { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, |
650 | { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, |
651 | { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, |
652 | { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, |
653 | { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, |
654 | { |
655 | .vendor = PCI_VENDOR_ID_MARVELL_EXT, |
656 | .device = 0x9480, |
657 | .subvendor = PCI_ANY_ID, |
658 | .subdevice = 0x9480, |
659 | .class = 0, |
660 | .class_mask = 0, |
661 | .driver_data = chip_9480, |
662 | }, |
663 | { |
664 | .vendor = PCI_VENDOR_ID_MARVELL_EXT, |
665 | .device = 0x9445, |
666 | .subvendor = PCI_ANY_ID, |
667 | .subdevice = 0x9480, |
668 | .class = 0, |
669 | .class_mask = 0, |
670 | .driver_data = chip_9445, |
671 | }, |
672 | { PCI_VDEVICE(MARVELL_EXT, 0x9485), chip_9485 }, /* Marvell 9480/9485 (any vendor/model) */ |
673 | { PCI_VDEVICE(OCZ, 0x1021), chip_9485}, /* OCZ RevoDrive3 */ |
674 | { PCI_VDEVICE(OCZ, 0x1022), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
675 | { PCI_VDEVICE(OCZ, 0x1040), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
676 | { PCI_VDEVICE(OCZ, 0x1041), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
677 | { PCI_VDEVICE(OCZ, 0x1042), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
678 | { PCI_VDEVICE(OCZ, 0x1043), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
679 | { PCI_VDEVICE(OCZ, 0x1044), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
680 | { PCI_VDEVICE(OCZ, 0x1080), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
681 | { PCI_VDEVICE(OCZ, 0x1083), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
682 | { PCI_VDEVICE(OCZ, 0x1084), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ |
683 | |
684 | { } /* terminate list */ |
685 | }; |
686 | |
687 | static struct pci_driver mvs_pci_driver = { |
688 | .name = DRV_NAME, |
689 | .id_table = mvs_pci_table, |
690 | .probe = mvs_pci_init, |
691 | .remove = mvs_pci_remove, |
692 | }; |
693 | |
694 | static ssize_t driver_version_show(struct device *cdev, |
695 | struct device_attribute *attr, char *buffer) |
696 | { |
697 | return sysfs_emit(buf: buffer, fmt: "%s\n" , DRV_VERSION); |
698 | } |
699 | |
700 | static DEVICE_ATTR_RO(driver_version); |
701 | |
702 | static ssize_t interrupt_coalescing_store(struct device *cdev, |
703 | struct device_attribute *attr, |
704 | const char *buffer, size_t size) |
705 | { |
706 | unsigned int val = 0; |
707 | struct mvs_info *mvi = NULL; |
708 | struct Scsi_Host *shost = class_to_shost(cdev); |
709 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
710 | u8 i, core_nr; |
711 | if (buffer == NULL) |
712 | return size; |
713 | |
714 | if (sscanf(buffer, "%u" , &val) != 1) |
715 | return -EINVAL; |
716 | |
717 | if (val >= 0x10000) { |
718 | mv_dprintk("interrupt coalescing timer %d us is" |
719 | "too long\n" , val); |
720 | return strlen(buffer); |
721 | } |
722 | |
723 | interrupt_coalescing = val; |
724 | |
725 | core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; |
726 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; |
727 | |
728 | if (unlikely(!mvi)) |
729 | return -EINVAL; |
730 | |
731 | for (i = 0; i < core_nr; i++) { |
732 | mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; |
733 | if (MVS_CHIP_DISP->tune_interrupt) |
734 | MVS_CHIP_DISP->tune_interrupt(mvi, |
735 | interrupt_coalescing); |
736 | } |
737 | mv_dprintk("set interrupt coalescing time to %d us\n" , |
738 | interrupt_coalescing); |
739 | return strlen(buffer); |
740 | } |
741 | |
742 | static ssize_t interrupt_coalescing_show(struct device *cdev, |
743 | struct device_attribute *attr, char *buffer) |
744 | { |
745 | return sysfs_emit(buf: buffer, fmt: "%d\n" , interrupt_coalescing); |
746 | } |
747 | |
748 | static DEVICE_ATTR_RW(interrupt_coalescing); |
749 | |
750 | static int __init mvs_init(void) |
751 | { |
752 | int rc; |
753 | mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); |
754 | if (!mvs_stt) |
755 | return -ENOMEM; |
756 | |
757 | rc = pci_register_driver(&mvs_pci_driver); |
758 | if (rc) |
759 | goto err_out; |
760 | |
761 | return 0; |
762 | |
763 | err_out: |
764 | sas_release_transport(mvs_stt); |
765 | return rc; |
766 | } |
767 | |
768 | static void __exit mvs_exit(void) |
769 | { |
770 | pci_unregister_driver(dev: &mvs_pci_driver); |
771 | sas_release_transport(mvs_stt); |
772 | } |
773 | |
774 | static struct attribute *mvst_host_attrs[] = { |
775 | &dev_attr_driver_version.attr, |
776 | &dev_attr_interrupt_coalescing.attr, |
777 | NULL, |
778 | }; |
779 | |
780 | ATTRIBUTE_GROUPS(mvst_host); |
781 | |
782 | module_init(mvs_init); |
783 | module_exit(mvs_exit); |
784 | |
785 | MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>" ); |
786 | MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver" ); |
787 | MODULE_VERSION(DRV_VERSION); |
788 | MODULE_LICENSE("GPL" ); |
789 | #ifdef CONFIG_PCI |
790 | MODULE_DEVICE_TABLE(pci, mvs_pci_table); |
791 | #endif |
792 | |