diff options
Diffstat (limited to 'drivers/scsi/sata_nv.c')
-rw-r--r-- | drivers/scsi/sata_nv.c | 181 |
1 files changed, 62 insertions, 119 deletions
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index e5b20c6afc18..f77bf183dfab 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c | |||
@@ -29,34 +29,6 @@ | |||
29 | * NV-specific details such as register offsets, SATA phy location, | 29 | * NV-specific details such as register offsets, SATA phy location, |
30 | * hotplug info, etc. | 30 | * hotplug info, etc. |
31 | * | 31 | * |
32 | * 0.10 | ||
33 | * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB | ||
34 | * drive. Also made the check_hotplug() callbacks return whether there | ||
35 | * was a hotplug interrupt or not. This was not the source of the | ||
36 | * spurious interrupts, but is the right thing to do anyway. | ||
37 | * | ||
38 | * 0.09 | ||
39 | * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. | ||
40 | * | ||
41 | * 0.08 | ||
42 | * - Added support for MCP51 and MCP55. | ||
43 | * | ||
44 | * 0.07 | ||
45 | * - Added support for RAID class code. | ||
46 | * | ||
47 | * 0.06 | ||
48 | * - Added generic SATA support by using a pci_device_id that filters on | ||
49 | * the IDE storage class code. | ||
50 | * | ||
51 | * 0.03 | ||
52 | * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using | ||
53 | * mmio_base, which is only set for the CK804/MCP04 case. | ||
54 | * | ||
55 | * 0.02 | ||
56 | * - Added support for CK804 SATA controller. | ||
57 | * | ||
58 | * 0.01 | ||
59 | * - Initial revision. | ||
60 | */ | 32 | */ |
61 | 33 | ||
62 | #include <linux/config.h> | 34 | #include <linux/config.h> |
@@ -74,53 +46,55 @@ | |||
74 | #define DRV_NAME "sata_nv" | 46 | #define DRV_NAME "sata_nv" |
75 | #define DRV_VERSION "0.8" | 47 | #define DRV_VERSION "0.8" |
76 | 48 | ||
77 | #define NV_PORTS 2 | 49 | enum { |
78 | #define NV_PIO_MASK 0x1f | 50 | NV_PORTS = 2, |
79 | #define NV_MWDMA_MASK 0x07 | 51 | NV_PIO_MASK = 0x1f, |
80 | #define NV_UDMA_MASK 0x7f | 52 | NV_MWDMA_MASK = 0x07, |
81 | #define NV_PORT0_SCR_REG_OFFSET 0x00 | 53 | NV_UDMA_MASK = 0x7f, |
82 | #define NV_PORT1_SCR_REG_OFFSET 0x40 | 54 | NV_PORT0_SCR_REG_OFFSET = 0x00, |
83 | 55 | NV_PORT1_SCR_REG_OFFSET = 0x40, | |
84 | #define NV_INT_STATUS 0x10 | 56 | |
85 | #define NV_INT_STATUS_CK804 0x440 | 57 | NV_INT_STATUS = 0x10, |
86 | #define NV_INT_STATUS_PDEV_INT 0x01 | 58 | NV_INT_STATUS_CK804 = 0x440, |
87 | #define NV_INT_STATUS_PDEV_PM 0x02 | 59 | NV_INT_STATUS_PDEV_INT = 0x01, |
88 | #define NV_INT_STATUS_PDEV_ADDED 0x04 | 60 | NV_INT_STATUS_PDEV_PM = 0x02, |
89 | #define NV_INT_STATUS_PDEV_REMOVED 0x08 | 61 | NV_INT_STATUS_PDEV_ADDED = 0x04, |
90 | #define NV_INT_STATUS_SDEV_INT 0x10 | 62 | NV_INT_STATUS_PDEV_REMOVED = 0x08, |
91 | #define NV_INT_STATUS_SDEV_PM 0x20 | 63 | NV_INT_STATUS_SDEV_INT = 0x10, |
92 | #define NV_INT_STATUS_SDEV_ADDED 0x40 | 64 | NV_INT_STATUS_SDEV_PM = 0x20, |
93 | #define NV_INT_STATUS_SDEV_REMOVED 0x80 | 65 | NV_INT_STATUS_SDEV_ADDED = 0x40, |
94 | #define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \ | 66 | NV_INT_STATUS_SDEV_REMOVED = 0x80, |
95 | NV_INT_STATUS_PDEV_REMOVED) | 67 | NV_INT_STATUS_PDEV_HOTPLUG = (NV_INT_STATUS_PDEV_ADDED | |
96 | #define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \ | 68 | NV_INT_STATUS_PDEV_REMOVED), |
97 | NV_INT_STATUS_SDEV_REMOVED) | 69 | NV_INT_STATUS_SDEV_HOTPLUG = (NV_INT_STATUS_SDEV_ADDED | |
98 | #define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \ | 70 | NV_INT_STATUS_SDEV_REMOVED), |
99 | NV_INT_STATUS_SDEV_HOTPLUG) | 71 | NV_INT_STATUS_HOTPLUG = (NV_INT_STATUS_PDEV_HOTPLUG | |
100 | 72 | NV_INT_STATUS_SDEV_HOTPLUG), | |
101 | #define NV_INT_ENABLE 0x11 | 73 | |
102 | #define NV_INT_ENABLE_CK804 0x441 | 74 | NV_INT_ENABLE = 0x11, |
103 | #define NV_INT_ENABLE_PDEV_MASK 0x01 | 75 | NV_INT_ENABLE_CK804 = 0x441, |
104 | #define NV_INT_ENABLE_PDEV_PM 0x02 | 76 | NV_INT_ENABLE_PDEV_MASK = 0x01, |
105 | #define NV_INT_ENABLE_PDEV_ADDED 0x04 | 77 | NV_INT_ENABLE_PDEV_PM = 0x02, |
106 | #define NV_INT_ENABLE_PDEV_REMOVED 0x08 | 78 | NV_INT_ENABLE_PDEV_ADDED = 0x04, |
107 | #define NV_INT_ENABLE_SDEV_MASK 0x10 | 79 | NV_INT_ENABLE_PDEV_REMOVED = 0x08, |
108 | #define NV_INT_ENABLE_SDEV_PM 0x20 | 80 | NV_INT_ENABLE_SDEV_MASK = 0x10, |
109 | #define NV_INT_ENABLE_SDEV_ADDED 0x40 | 81 | NV_INT_ENABLE_SDEV_PM = 0x20, |
110 | #define NV_INT_ENABLE_SDEV_REMOVED 0x80 | 82 | NV_INT_ENABLE_SDEV_ADDED = 0x40, |
111 | #define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \ | 83 | NV_INT_ENABLE_SDEV_REMOVED = 0x80, |
112 | NV_INT_ENABLE_PDEV_REMOVED) | 84 | NV_INT_ENABLE_PDEV_HOTPLUG = (NV_INT_ENABLE_PDEV_ADDED | |
113 | #define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \ | 85 | NV_INT_ENABLE_PDEV_REMOVED), |
114 | NV_INT_ENABLE_SDEV_REMOVED) | 86 | NV_INT_ENABLE_SDEV_HOTPLUG = (NV_INT_ENABLE_SDEV_ADDED | |
115 | #define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \ | 87 | NV_INT_ENABLE_SDEV_REMOVED), |
116 | NV_INT_ENABLE_SDEV_HOTPLUG) | 88 | NV_INT_ENABLE_HOTPLUG = (NV_INT_ENABLE_PDEV_HOTPLUG | |
117 | 89 | NV_INT_ENABLE_SDEV_HOTPLUG), | |
118 | #define NV_INT_CONFIG 0x12 | 90 | |
119 | #define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI | 91 | NV_INT_CONFIG = 0x12, |
120 | 92 | NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI | |
121 | // For PCI config register 20 | 93 | |
122 | #define NV_MCP_SATA_CFG_20 0x50 | 94 | // For PCI config register 20 |
123 | #define NV_MCP_SATA_CFG_20_SATA_SPACE_EN 0x04 | 95 | NV_MCP_SATA_CFG_20 = 0x50, |
96 | NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04, | ||
97 | }; | ||
124 | 98 | ||
125 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); | 99 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); |
126 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, | 100 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, |
@@ -175,8 +149,6 @@ static const struct pci_device_id nv_pci_tbl[] = { | |||
175 | { 0, } /* terminate list */ | 149 | { 0, } /* terminate list */ |
176 | }; | 150 | }; |
177 | 151 | ||
178 | #define NV_HOST_FLAGS_SCR_MMIO 0x00000001 | ||
179 | |||
180 | struct nv_host_desc | 152 | struct nv_host_desc |
181 | { | 153 | { |
182 | enum nv_host_type host_type; | 154 | enum nv_host_type host_type; |
@@ -332,36 +304,23 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, | |||
332 | 304 | ||
333 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) | 305 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) |
334 | { | 306 | { |
335 | struct ata_host_set *host_set = ap->host_set; | ||
336 | struct nv_host *host = host_set->private_data; | ||
337 | |||
338 | if (sc_reg > SCR_CONTROL) | 307 | if (sc_reg > SCR_CONTROL) |
339 | return 0xffffffffU; | 308 | return 0xffffffffU; |
340 | 309 | ||
341 | if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) | 310 | return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); |
342 | return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); | ||
343 | else | ||
344 | return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); | ||
345 | } | 311 | } |
346 | 312 | ||
347 | static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) | 313 | static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) |
348 | { | 314 | { |
349 | struct ata_host_set *host_set = ap->host_set; | ||
350 | struct nv_host *host = host_set->private_data; | ||
351 | |||
352 | if (sc_reg > SCR_CONTROL) | 315 | if (sc_reg > SCR_CONTROL) |
353 | return; | 316 | return; |
354 | 317 | ||
355 | if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) | 318 | iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); |
356 | writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); | ||
357 | else | ||
358 | outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); | ||
359 | } | 319 | } |
360 | 320 | ||
361 | static void nv_host_stop (struct ata_host_set *host_set) | 321 | static void nv_host_stop (struct ata_host_set *host_set) |
362 | { | 322 | { |
363 | struct nv_host *host = host_set->private_data; | 323 | struct nv_host *host = host_set->private_data; |
364 | struct pci_dev *pdev = to_pci_dev(host_set->dev); | ||
365 | 324 | ||
366 | // Disable hotplug event interrupts. | 325 | // Disable hotplug event interrupts. |
367 | if (host->host_desc->disable_hotplug) | 326 | if (host->host_desc->disable_hotplug) |
@@ -369,8 +328,7 @@ static void nv_host_stop (struct ata_host_set *host_set) | |||
369 | 328 | ||
370 | kfree(host); | 329 | kfree(host); |
371 | 330 | ||
372 | if (host_set->mmio_base) | 331 | ata_pci_host_stop(host_set); |
373 | pci_iounmap(pdev, host_set->mmio_base); | ||
374 | } | 332 | } |
375 | 333 | ||
376 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | 334 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) |
@@ -382,6 +340,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
382 | int pci_dev_busy = 0; | 340 | int pci_dev_busy = 0; |
383 | int rc; | 341 | int rc; |
384 | u32 bar; | 342 | u32 bar; |
343 | unsigned long base; | ||
385 | 344 | ||
386 | // Make sure this is a SATA controller by counting the number of bars | 345 | // Make sure this is a SATA controller by counting the number of bars |
387 | // (NVIDIA SATA controllers will always have six bars). Otherwise, | 346 | // (NVIDIA SATA controllers will always have six bars). Otherwise, |
@@ -426,31 +385,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
426 | 385 | ||
427 | probe_ent->private_data = host; | 386 | probe_ent->private_data = host; |
428 | 387 | ||
429 | if (pci_resource_flags(pdev, 5) & IORESOURCE_MEM) | 388 | probe_ent->mmio_base = pci_iomap(pdev, 5, 0); |
430 | host->host_flags |= NV_HOST_FLAGS_SCR_MMIO; | 389 | if (!probe_ent->mmio_base) { |
431 | 390 | rc = -EIO; | |
432 | if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) { | 391 | goto err_out_free_host; |
433 | unsigned long base; | 392 | } |
434 | |||
435 | probe_ent->mmio_base = pci_iomap(pdev, 5, 0); | ||
436 | if (probe_ent->mmio_base == NULL) { | ||
437 | rc = -EIO; | ||
438 | goto err_out_free_host; | ||
439 | } | ||
440 | |||
441 | base = (unsigned long)probe_ent->mmio_base; | ||
442 | 393 | ||
443 | probe_ent->port[0].scr_addr = | 394 | base = (unsigned long)probe_ent->mmio_base; |
444 | base + NV_PORT0_SCR_REG_OFFSET; | ||
445 | probe_ent->port[1].scr_addr = | ||
446 | base + NV_PORT1_SCR_REG_OFFSET; | ||
447 | } else { | ||
448 | 395 | ||
449 | probe_ent->port[0].scr_addr = | 396 | probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; |
450 | pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET; | 397 | probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; |
451 | probe_ent->port[1].scr_addr = | ||
452 | pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET; | ||
453 | } | ||
454 | 398 | ||
455 | pci_set_master(pdev); | 399 | pci_set_master(pdev); |
456 | 400 | ||
@@ -467,8 +411,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
467 | return 0; | 411 | return 0; |
468 | 412 | ||
469 | err_out_iounmap: | 413 | err_out_iounmap: |
470 | if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) | 414 | pci_iounmap(pdev, probe_ent->mmio_base); |
471 | pci_iounmap(pdev, probe_ent->mmio_base); | ||
472 | err_out_free_host: | 415 | err_out_free_host: |
473 | kfree(host); | 416 | kfree(host); |
474 | err_out_free_ent: | 417 | err_out_free_ent: |