diff options
author | Sergei Shtylyov <sshtylyov@ru.mvista.com> | 2006-12-13 03:35:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-13 12:05:55 -0500 |
commit | 33b18a602525198ab8892789dab6839f325407f8 (patch) | |
tree | a5bad1aa24780df54d2c8b6e0d6cb6823caa3481 | |
parent | 471a0bda5a2de5b0fd3b58255791eb831517a52c (diff) |
[PATCH] ide: fix HPT3xx hotswap support
Fix the broken hotswap code: on HPT37x it caused RESET- to glitch when
tristating the bus (the MISC control 3/6 and soft control 2 need to be written
to in the certain order), and for HPT36x the obsolete HDIO_TRISTATE_HWIF
ioctl() handler was called instead which treated the state argument wrong.
Also, get rid of the soft control reg. 1 wtite to enable IDE interrupt --
this is done in init_hpt37x() already...
Have been tested on HPT370 and 371N.
Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/ide/pci/hpt366.c | 115 |
1 files changed, 36 insertions, 79 deletions
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 787efd35db2b..29a377044323 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c | |||
@@ -70,6 +70,8 @@ | |||
70 | * - fix/remove bad/unused timing tables and use one set of tables for the whole | 70 | * - fix/remove bad/unused timing tables and use one set of tables for the whole |
71 | * HPT37x chip family; save space by introducing the separate transfer mode | 71 | * HPT37x chip family; save space by introducing the separate transfer mode |
72 | * table in which the mode lookup is done | 72 | * table in which the mode lookup is done |
73 | * - fix the hotswap code: it caused RESET- to glitch when tristating the bus, | ||
74 | * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead | ||
73 | * <source@mvista.com> | 75 | * <source@mvista.com> |
74 | * | 76 | * |
75 | */ | 77 | */ |
@@ -914,101 +916,68 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) | |||
914 | hpt3xxn_set_clock(hwif, wantclock); | 916 | hpt3xxn_set_clock(hwif, wantclock); |
915 | } | 917 | } |
916 | 918 | ||
917 | /* | ||
918 | * Since SUN Cobalt is attempting to do this operation, I should disclose | ||
919 | * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date | ||
920 | * HOTSWAP ATA Infrastructure. | ||
921 | */ | ||
922 | |||
923 | static void hpt3xx_reset (ide_drive_t *drive) | ||
924 | { | ||
925 | } | ||
926 | |||
927 | static int hpt3xx_tristate (ide_drive_t * drive, int state) | ||
928 | { | ||
929 | ide_hwif_t *hwif = HWIF(drive); | ||
930 | struct pci_dev *dev = hwif->pci_dev; | ||
931 | u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; | ||
932 | u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; | ||
933 | |||
934 | pci_read_config_byte(dev, 0x59, ®59h); | ||
935 | pci_read_config_byte(dev, state_reg, ®XXh); | ||
936 | |||
937 | if (state) { | ||
938 | (void) ide_do_reset(drive); | ||
939 | pci_write_config_byte(dev, state_reg, regXXh|0x80); | ||
940 | pci_write_config_byte(dev, 0x59, reg59h|reset); | ||
941 | } else { | ||
942 | pci_write_config_byte(dev, 0x59, reg59h & ~(reset)); | ||
943 | pci_write_config_byte(dev, state_reg, regXXh & ~(0x80)); | ||
944 | (void) ide_do_reset(drive); | ||
945 | } | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | /* | 919 | /* |
950 | * set/get power state for a drive. | 920 | * Set/get power state for a drive. |
951 | * turning the power off does the following things: | ||
952 | * 1) soft-reset the drive | ||
953 | * 2) tri-states the ide bus | ||
954 | * | 921 | * |
955 | * when we turn things back on, we need to re-initialize things. | 922 | * When we turn the power back on, we need to re-initialize things. |
956 | */ | 923 | */ |
957 | #define TRISTATE_BIT 0x8000 | 924 | #define TRISTATE_BIT 0x8000 |
958 | static int hpt370_busproc(ide_drive_t * drive, int state) | 925 | |
926 | static int hpt3xx_busproc(ide_drive_t *drive, int state) | ||
959 | { | 927 | { |
960 | ide_hwif_t *hwif = drive->hwif; | 928 | ide_hwif_t *hwif = drive->hwif; |
961 | struct pci_dev *dev = hwif->pci_dev; | 929 | struct pci_dev *dev = hwif->pci_dev; |
962 | u8 tristate = 0, resetmask = 0, bus_reg = 0; | 930 | u8 tristate, resetmask, bus_reg = 0; |
963 | u16 tri_reg; | 931 | u16 tri_reg = 0; |
964 | 932 | ||
965 | hwif->bus_state = state; | 933 | hwif->bus_state = state; |
966 | 934 | ||
967 | if (hwif->channel) { | 935 | if (hwif->channel) { |
968 | /* secondary channel */ | 936 | /* secondary channel */ |
969 | tristate = 0x56; | 937 | tristate = 0x56; |
970 | resetmask = 0x80; | 938 | resetmask = 0x80; |
971 | } else { | 939 | } else { |
972 | /* primary channel */ | 940 | /* primary channel */ |
973 | tristate = 0x52; | 941 | tristate = 0x52; |
974 | resetmask = 0x40; | 942 | resetmask = 0x40; |
975 | } | 943 | } |
976 | 944 | ||
977 | /* grab status */ | 945 | /* Grab the status. */ |
978 | pci_read_config_word(dev, tristate, &tri_reg); | 946 | pci_read_config_word(dev, tristate, &tri_reg); |
979 | pci_read_config_byte(dev, 0x59, &bus_reg); | 947 | pci_read_config_byte(dev, 0x59, &bus_reg); |
980 | 948 | ||
981 | /* set the state. we don't set it if we don't need to do so. | 949 | /* |
982 | * make sure that the drive knows that it has failed if it's off */ | 950 | * Set the state. We don't set it if we don't need to do so. |
951 | * Make sure that the drive knows that it has failed if it's off. | ||
952 | */ | ||
983 | switch (state) { | 953 | switch (state) { |
984 | case BUSSTATE_ON: | 954 | case BUSSTATE_ON: |
985 | hwif->drives[0].failures = 0; | 955 | if (!(bus_reg & resetmask)) |
986 | hwif->drives[1].failures = 0; | ||
987 | if ((bus_reg & resetmask) == 0) | ||
988 | return 0; | 956 | return 0; |
989 | tri_reg &= ~TRISTATE_BIT; | 957 | hwif->drives[0].failures = hwif->drives[1].failures = 0; |
990 | bus_reg &= ~resetmask; | 958 | |
991 | break; | 959 | pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask); |
960 | pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT); | ||
961 | return 0; | ||
992 | case BUSSTATE_OFF: | 962 | case BUSSTATE_OFF: |
993 | hwif->drives[0].failures = hwif->drives[0].max_failures + 1; | 963 | if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT)) |
994 | hwif->drives[1].failures = hwif->drives[1].max_failures + 1; | ||
995 | if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask)) | ||
996 | return 0; | 964 | return 0; |
997 | tri_reg &= ~TRISTATE_BIT; | 965 | tri_reg &= ~TRISTATE_BIT; |
998 | bus_reg |= resetmask; | ||
999 | break; | 966 | break; |
1000 | case BUSSTATE_TRISTATE: | 967 | case BUSSTATE_TRISTATE: |
1001 | hwif->drives[0].failures = hwif->drives[0].max_failures + 1; | 968 | if ((bus_reg & resetmask) && (tri_reg & TRISTATE_BIT)) |
1002 | hwif->drives[1].failures = hwif->drives[1].max_failures + 1; | ||
1003 | if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask)) | ||
1004 | return 0; | 969 | return 0; |
1005 | tri_reg |= TRISTATE_BIT; | 970 | tri_reg |= TRISTATE_BIT; |
1006 | bus_reg |= resetmask; | ||
1007 | break; | 971 | break; |
972 | default: | ||
973 | return -EINVAL; | ||
1008 | } | 974 | } |
1009 | pci_write_config_byte(dev, 0x59, bus_reg); | ||
1010 | pci_write_config_word(dev, tristate, tri_reg); | ||
1011 | 975 | ||
976 | hwif->drives[0].failures = hwif->drives[0].max_failures + 1; | ||
977 | hwif->drives[1].failures = hwif->drives[1].max_failures + 1; | ||
978 | |||
979 | pci_write_config_word(dev, tristate, tri_reg); | ||
980 | pci_write_config_byte(dev, 0x59, bus_reg | resetmask); | ||
1012 | return 0; | 981 | return 0; |
1013 | } | 982 | } |
1014 | 983 | ||
@@ -1306,23 +1275,11 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) | |||
1306 | if (serialize && hwif->mate) | 1275 | if (serialize && hwif->mate) |
1307 | hwif->serialized = hwif->mate->serialized = 1; | 1276 | hwif->serialized = hwif->mate->serialized = 1; |
1308 | 1277 | ||
1309 | if (info->revision >= 3) { | 1278 | /* |
1310 | u8 reg5ah = 0; | 1279 | * Set up ioctl for power status. |
1311 | pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); | 1280 | * NOTE: power affects both drives on each channel. |
1312 | /* | 1281 | */ |
1313 | * set up ioctl for power status. | 1282 | hwif->busproc = &hpt3xx_busproc; |
1314 | * note: power affects both | ||
1315 | * drives on each channel | ||
1316 | */ | ||
1317 | hwif->resetproc = &hpt3xx_reset; | ||
1318 | hwif->busproc = &hpt370_busproc; | ||
1319 | } else if (info->revision >= 2) { | ||
1320 | hwif->resetproc = &hpt3xx_reset; | ||
1321 | hwif->busproc = &hpt3xx_tristate; | ||
1322 | } else { | ||
1323 | hwif->resetproc = &hpt3xx_reset; | ||
1324 | hwif->busproc = &hpt3xx_tristate; | ||
1325 | } | ||
1326 | 1283 | ||
1327 | if (!hwif->dma_base) { | 1284 | if (!hwif->dma_base) { |
1328 | hwif->drives[0].autotune = 1; | 1285 | hwif->drives[0].autotune = 1; |