aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/pci/hpt366.c
diff options
context:
space:
mode:
authorSergei Shtylyov <sshtylyov@ru.mvista.com>2006-12-13 03:35:50 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-13 12:05:55 -0500
commit33b18a602525198ab8892789dab6839f325407f8 (patch)
treea5bad1aa24780df54d2c8b6e0d6cb6823caa3481 /drivers/ide/pci/hpt366.c
parent471a0bda5a2de5b0fd3b58255791eb831517a52c (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>
Diffstat (limited to 'drivers/ide/pci/hpt366.c')
-rw-r--r--drivers/ide/pci/hpt366.c115
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
923static void hpt3xx_reset (ide_drive_t *drive)
924{
925}
926
927static 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, &reg59h);
935 pci_read_config_byte(dev, state_reg, &regXXh);
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
958static int hpt370_busproc(ide_drive_t * drive, int state) 925
926static 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;