diff options
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 103 |
1 files changed, 78 insertions, 25 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index da5bd33d982d..9a547ca9c864 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -32,13 +32,14 @@ | |||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/dma-mapping.h> | ||
35 | #include "scsi.h" | 36 | #include "scsi.h" |
36 | #include <scsi/scsi_host.h> | 37 | #include <scsi/scsi_host.h> |
37 | #include <linux/libata.h> | 38 | #include <linux/libata.h> |
38 | #include <asm/io.h> | 39 | #include <asm/io.h> |
39 | 40 | ||
40 | #define DRV_NAME "ahci" | 41 | #define DRV_NAME "ahci" |
41 | #define DRV_VERSION "1.00" | 42 | #define DRV_VERSION "1.01" |
42 | 43 | ||
43 | 44 | ||
44 | enum { | 45 | enum { |
@@ -49,6 +50,7 @@ enum { | |||
49 | AHCI_CMD_SLOT_SZ = 32 * 32, | 50 | AHCI_CMD_SLOT_SZ = 32 * 32, |
50 | AHCI_RX_FIS_SZ = 256, | 51 | AHCI_RX_FIS_SZ = 256, |
51 | AHCI_CMD_TBL_HDR = 0x80, | 52 | AHCI_CMD_TBL_HDR = 0x80, |
53 | AHCI_CMD_TBL_CDB = 0x40, | ||
52 | AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16), | 54 | AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16), |
53 | AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ + | 55 | AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ + |
54 | AHCI_RX_FIS_SZ, | 56 | AHCI_RX_FIS_SZ, |
@@ -133,6 +135,9 @@ enum { | |||
133 | PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ | 135 | PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ |
134 | PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ | 136 | PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ |
135 | PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ | 137 | PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ |
138 | |||
139 | /* hpriv->flags bits */ | ||
140 | AHCI_FLAG_MSI = (1 << 0), | ||
136 | }; | 141 | }; |
137 | 142 | ||
138 | struct ahci_cmd_hdr { | 143 | struct ahci_cmd_hdr { |
@@ -182,6 +187,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc); | |||
182 | static u8 ahci_check_status(struct ata_port *ap); | 187 | static u8 ahci_check_status(struct ata_port *ap); |
183 | static u8 ahci_check_err(struct ata_port *ap); | 188 | static u8 ahci_check_err(struct ata_port *ap); |
184 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); | 189 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); |
190 | static void ahci_remove_one (struct pci_dev *pdev); | ||
185 | 191 | ||
186 | static Scsi_Host_Template ahci_sht = { | 192 | static Scsi_Host_Template ahci_sht = { |
187 | .module = THIS_MODULE, | 193 | .module = THIS_MODULE, |
@@ -271,7 +277,7 @@ static struct pci_driver ahci_pci_driver = { | |||
271 | .name = DRV_NAME, | 277 | .name = DRV_NAME, |
272 | .id_table = ahci_pci_tbl, | 278 | .id_table = ahci_pci_tbl, |
273 | .probe = ahci_init_one, | 279 | .probe = ahci_init_one, |
274 | .remove = ata_pci_remove_one, | 280 | .remove = ahci_remove_one, |
275 | }; | 281 | }; |
276 | 282 | ||
277 | 283 | ||
@@ -289,6 +295,8 @@ static void ahci_host_stop(struct ata_host_set *host_set) | |||
289 | { | 295 | { |
290 | struct ahci_host_priv *hpriv = host_set->private_data; | 296 | struct ahci_host_priv *hpriv = host_set->private_data; |
291 | kfree(hpriv); | 297 | kfree(hpriv); |
298 | |||
299 | ata_host_stop(host_set); | ||
292 | } | 300 | } |
293 | 301 | ||
294 | static int ahci_port_start(struct ata_port *ap) | 302 | static int ahci_port_start(struct ata_port *ap) |
@@ -503,7 +511,8 @@ static void ahci_fill_sg(struct ata_queued_cmd *qc) | |||
503 | 511 | ||
504 | static void ahci_qc_prep(struct ata_queued_cmd *qc) | 512 | static void ahci_qc_prep(struct ata_queued_cmd *qc) |
505 | { | 513 | { |
506 | struct ahci_port_priv *pp = qc->ap->private_data; | 514 | struct ata_port *ap = qc->ap; |
515 | struct ahci_port_priv *pp = ap->private_data; | ||
507 | u32 opts; | 516 | u32 opts; |
508 | const u32 cmd_fis_len = 5; /* five dwords */ | 517 | const u32 cmd_fis_len = 5; /* five dwords */ |
509 | 518 | ||
@@ -515,18 +524,8 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) | |||
515 | opts = (qc->n_elem << 16) | cmd_fis_len; | 524 | opts = (qc->n_elem << 16) | cmd_fis_len; |
516 | if (qc->tf.flags & ATA_TFLAG_WRITE) | 525 | if (qc->tf.flags & ATA_TFLAG_WRITE) |
517 | opts |= AHCI_CMD_WRITE; | 526 | opts |= AHCI_CMD_WRITE; |
518 | 527 | if (is_atapi_taskfile(&qc->tf)) | |
519 | switch (qc->tf.protocol) { | ||
520 | case ATA_PROT_ATAPI: | ||
521 | case ATA_PROT_ATAPI_NODATA: | ||
522 | case ATA_PROT_ATAPI_DMA: | ||
523 | opts |= AHCI_CMD_ATAPI; | 528 | opts |= AHCI_CMD_ATAPI; |
524 | break; | ||
525 | |||
526 | default: | ||
527 | /* do nothing */ | ||
528 | break; | ||
529 | } | ||
530 | 529 | ||
531 | pp->cmd_slot[0].opts = cpu_to_le32(opts); | 530 | pp->cmd_slot[0].opts = cpu_to_le32(opts); |
532 | pp->cmd_slot[0].status = 0; | 531 | pp->cmd_slot[0].status = 0; |
@@ -538,6 +537,10 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) | |||
538 | * a SATA Register - Host to Device command FIS. | 537 | * a SATA Register - Host to Device command FIS. |
539 | */ | 538 | */ |
540 | ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0); | 539 | ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0); |
540 | if (opts & AHCI_CMD_ATAPI) { | ||
541 | memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32); | ||
542 | memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len); | ||
543 | } | ||
541 | 544 | ||
542 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) | 545 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) |
543 | return; | 546 | return; |
@@ -792,8 +795,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
792 | return rc; | 795 | return rc; |
793 | } | 796 | } |
794 | } | 797 | } |
795 | |||
796 | hpriv->flags |= HOST_CAP_64; | ||
797 | } else { | 798 | } else { |
798 | rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | 799 | rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); |
799 | if (rc) { | 800 | if (rc) { |
@@ -876,15 +877,19 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
876 | } | 877 | } |
877 | 878 | ||
878 | /* move to PCI layer, integrate w/ MSI stuff */ | 879 | /* move to PCI layer, integrate w/ MSI stuff */ |
879 | static void pci_enable_intx(struct pci_dev *pdev) | 880 | static void pci_intx(struct pci_dev *pdev, int enable) |
880 | { | 881 | { |
881 | u16 pci_command; | 882 | u16 pci_command, new; |
882 | 883 | ||
883 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); | 884 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); |
884 | if (pci_command & PCI_COMMAND_INTX_DISABLE) { | 885 | |
885 | pci_command &= ~PCI_COMMAND_INTX_DISABLE; | 886 | if (enable) |
887 | new = pci_command & ~PCI_COMMAND_INTX_DISABLE; | ||
888 | else | ||
889 | new = pci_command | PCI_COMMAND_INTX_DISABLE; | ||
890 | |||
891 | if (new != pci_command) | ||
886 | pci_write_config_word(pdev, PCI_COMMAND, pci_command); | 892 | pci_write_config_word(pdev, PCI_COMMAND, pci_command); |
887 | } | ||
888 | } | 893 | } |
889 | 894 | ||
890 | static void ahci_print_info(struct ata_probe_ent *probe_ent) | 895 | static void ahci_print_info(struct ata_probe_ent *probe_ent) |
@@ -966,7 +971,7 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
966 | unsigned long base; | 971 | unsigned long base; |
967 | void *mmio_base; | 972 | void *mmio_base; |
968 | unsigned int board_idx = (unsigned int) ent->driver_data; | 973 | unsigned int board_idx = (unsigned int) ent->driver_data; |
969 | int pci_dev_busy = 0; | 974 | int have_msi, pci_dev_busy = 0; |
970 | int rc; | 975 | int rc; |
971 | 976 | ||
972 | VPRINTK("ENTER\n"); | 977 | VPRINTK("ENTER\n"); |
@@ -984,12 +989,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
984 | goto err_out; | 989 | goto err_out; |
985 | } | 990 | } |
986 | 991 | ||
987 | pci_enable_intx(pdev); | 992 | if (pci_enable_msi(pdev) == 0) |
993 | have_msi = 1; | ||
994 | else { | ||
995 | pci_intx(pdev, 1); | ||
996 | have_msi = 0; | ||
997 | } | ||
988 | 998 | ||
989 | probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); | 999 | probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); |
990 | if (probe_ent == NULL) { | 1000 | if (probe_ent == NULL) { |
991 | rc = -ENOMEM; | 1001 | rc = -ENOMEM; |
992 | goto err_out_regions; | 1002 | goto err_out_msi; |
993 | } | 1003 | } |
994 | 1004 | ||
995 | memset(probe_ent, 0, sizeof(*probe_ent)); | 1005 | memset(probe_ent, 0, sizeof(*probe_ent)); |
@@ -1022,6 +1032,9 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1022 | probe_ent->mmio_base = mmio_base; | 1032 | probe_ent->mmio_base = mmio_base; |
1023 | probe_ent->private_data = hpriv; | 1033 | probe_ent->private_data = hpriv; |
1024 | 1034 | ||
1035 | if (have_msi) | ||
1036 | hpriv->flags |= AHCI_FLAG_MSI; | ||
1037 | |||
1025 | /* initialize adapter */ | 1038 | /* initialize adapter */ |
1026 | rc = ahci_host_init(probe_ent); | 1039 | rc = ahci_host_init(probe_ent); |
1027 | if (rc) | 1040 | if (rc) |
@@ -1041,7 +1054,11 @@ err_out_iounmap: | |||
1041 | iounmap(mmio_base); | 1054 | iounmap(mmio_base); |
1042 | err_out_free_ent: | 1055 | err_out_free_ent: |
1043 | kfree(probe_ent); | 1056 | kfree(probe_ent); |
1044 | err_out_regions: | 1057 | err_out_msi: |
1058 | if (have_msi) | ||
1059 | pci_disable_msi(pdev); | ||
1060 | else | ||
1061 | pci_intx(pdev, 0); | ||
1045 | pci_release_regions(pdev); | 1062 | pci_release_regions(pdev); |
1046 | err_out: | 1063 | err_out: |
1047 | if (!pci_dev_busy) | 1064 | if (!pci_dev_busy) |
@@ -1049,6 +1066,42 @@ err_out: | |||
1049 | return rc; | 1066 | return rc; |
1050 | } | 1067 | } |
1051 | 1068 | ||
1069 | static void ahci_remove_one (struct pci_dev *pdev) | ||
1070 | { | ||
1071 | struct device *dev = pci_dev_to_dev(pdev); | ||
1072 | struct ata_host_set *host_set = dev_get_drvdata(dev); | ||
1073 | struct ahci_host_priv *hpriv = host_set->private_data; | ||
1074 | struct ata_port *ap; | ||
1075 | unsigned int i; | ||
1076 | int have_msi; | ||
1077 | |||
1078 | for (i = 0; i < host_set->n_ports; i++) { | ||
1079 | ap = host_set->ports[i]; | ||
1080 | |||
1081 | scsi_remove_host(ap->host); | ||
1082 | } | ||
1083 | |||
1084 | have_msi = hpriv->flags & AHCI_FLAG_MSI; | ||
1085 | free_irq(host_set->irq, host_set); | ||
1086 | |||
1087 | for (i = 0; i < host_set->n_ports; i++) { | ||
1088 | ap = host_set->ports[i]; | ||
1089 | |||
1090 | ata_scsi_release(ap->host); | ||
1091 | scsi_host_put(ap->host); | ||
1092 | } | ||
1093 | |||
1094 | host_set->ops->host_stop(host_set); | ||
1095 | kfree(host_set); | ||
1096 | |||
1097 | if (have_msi) | ||
1098 | pci_disable_msi(pdev); | ||
1099 | else | ||
1100 | pci_intx(pdev, 0); | ||
1101 | pci_release_regions(pdev); | ||
1102 | pci_disable_device(pdev); | ||
1103 | dev_set_drvdata(dev, NULL); | ||
1104 | } | ||
1052 | 1105 | ||
1053 | static int __init ahci_init(void) | 1106 | static int __init ahci_init(void) |
1054 | { | 1107 | { |