xref: /freebsd/sys/dev/ata/ata-sata.c (revision fdafd315)
113014ca0SSøren Schmidt /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
49a14aa01SUlrich Spörlein  * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
513014ca0SSøren Schmidt  * All rights reserved.
613014ca0SSøren Schmidt  *
713014ca0SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
813014ca0SSøren Schmidt  * modification, are permitted provided that the following conditions
913014ca0SSøren Schmidt  * are met:
1013014ca0SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
1113014ca0SSøren Schmidt  *    notice, this list of conditions and the following disclaimer,
1213014ca0SSøren Schmidt  *    without modification, immediately at the beginning of the file.
1313014ca0SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
1413014ca0SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
1513014ca0SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
1613014ca0SSøren Schmidt  *
1713014ca0SSøren Schmidt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1813014ca0SSøren Schmidt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1913014ca0SSøren Schmidt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2013014ca0SSøren Schmidt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2113014ca0SSøren Schmidt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2213014ca0SSøren Schmidt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2313014ca0SSøren Schmidt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2413014ca0SSøren Schmidt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2513014ca0SSøren Schmidt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2613014ca0SSøren Schmidt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2713014ca0SSøren Schmidt  */
2813014ca0SSøren Schmidt 
2913014ca0SSøren Schmidt #include <sys/param.h>
3013014ca0SSøren Schmidt #include <sys/systm.h>
3113014ca0SSøren Schmidt #include <sys/kernel.h>
3213014ca0SSøren Schmidt #include <sys/ata.h>
3313014ca0SSøren Schmidt #include <sys/bus.h>
3413014ca0SSøren Schmidt #include <sys/endian.h>
3513014ca0SSøren Schmidt #include <sys/malloc.h>
3613014ca0SSøren Schmidt #include <sys/lock.h>
3713014ca0SSøren Schmidt #include <sys/mutex.h>
3813014ca0SSøren Schmidt #include <sys/sema.h>
3913014ca0SSøren Schmidt #include <sys/taskqueue.h>
4013014ca0SSøren Schmidt #include <vm/uma.h>
4113014ca0SSøren Schmidt #include <machine/stdarg.h>
4213014ca0SSøren Schmidt #include <machine/resource.h>
4313014ca0SSøren Schmidt #include <machine/bus.h>
4413014ca0SSøren Schmidt #include <sys/rman.h>
4513014ca0SSøren Schmidt #include <dev/ata/ata-all.h>
4613014ca0SSøren Schmidt #include <ata_if.h>
4713014ca0SSøren Schmidt 
4813014ca0SSøren Schmidt void
ata_sata_phy_check_events(device_t dev,int port)49bda55b6aSAlexander Motin ata_sata_phy_check_events(device_t dev, int port)
5013014ca0SSøren Schmidt {
5113014ca0SSøren Schmidt     struct ata_channel *ch = device_get_softc(dev);
52bda55b6aSAlexander Motin     u_int32_t error, status;
5313014ca0SSøren Schmidt 
54f5d569f3SAlexander Motin     if (ata_sata_scr_read(ch, port, ATA_SERROR, &error))
55f5d569f3SAlexander Motin 	return;
560eac2d6bSAlexander Motin 
570eac2d6bSAlexander Motin     /* Check that SError value is sane. */
580eac2d6bSAlexander Motin     if (error == 0xffffffff)
590eac2d6bSAlexander Motin 	return;
600eac2d6bSAlexander Motin 
61bda55b6aSAlexander Motin     /* Clear set error bits/interrupt. */
62bda55b6aSAlexander Motin     if (error)
63bda55b6aSAlexander Motin 	ata_sata_scr_write(ch, port, ATA_SERROR, error);
6413014ca0SSøren Schmidt 
6513014ca0SSøren Schmidt     /* if we have a connection event deal with it */
664c10f2e6SAlexander Motin     if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) {
676030a3f0SAlexander Motin 	if (bootverbose) {
68f5d569f3SAlexander Motin 	    if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status)) {
69f5d569f3SAlexander Motin 		    device_printf(dev, "PHYRDY change\n");
70f5d569f3SAlexander Motin 	    } else if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
71bda55b6aSAlexander Motin 		((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
72bda55b6aSAlexander Motin 		((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) {
7313014ca0SSøren Schmidt 		    device_printf(dev, "CONNECT requested\n");
746030a3f0SAlexander Motin 	    } else
7513014ca0SSøren Schmidt 		    device_printf(dev, "DISCONNECT requested\n");
7613014ca0SSøren Schmidt 	}
776030a3f0SAlexander Motin 	taskqueue_enqueue(taskqueue_thread, &ch->conntask);
7813014ca0SSøren Schmidt     }
7913014ca0SSøren Schmidt }
8013014ca0SSøren Schmidt 
819cf4fe2eSAlexander Motin int
ata_sata_scr_read(struct ata_channel * ch,int port,int reg,uint32_t * val)829cf4fe2eSAlexander Motin ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val)
839cf4fe2eSAlexander Motin {
849cf4fe2eSAlexander Motin 
85bda55b6aSAlexander Motin     if (ch->hw.pm_read != NULL)
86bda55b6aSAlexander Motin 	return (ch->hw.pm_read(ch->dev, port, reg, val));
87bda55b6aSAlexander Motin     if (ch->r_io[reg].res) {
889cf4fe2eSAlexander Motin 	*val = ATA_IDX_INL(ch, reg);
899cf4fe2eSAlexander Motin 	return (0);
909cf4fe2eSAlexander Motin     }
91bda55b6aSAlexander Motin     return (-1);
929cf4fe2eSAlexander Motin }
939cf4fe2eSAlexander Motin 
949cf4fe2eSAlexander Motin int
ata_sata_scr_write(struct ata_channel * ch,int port,int reg,uint32_t val)959cf4fe2eSAlexander Motin ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val)
969cf4fe2eSAlexander Motin {
979cf4fe2eSAlexander Motin 
98bda55b6aSAlexander Motin     if (ch->hw.pm_write != NULL)
99bda55b6aSAlexander Motin 	return (ch->hw.pm_write(ch->dev, port, reg, val));
100bda55b6aSAlexander Motin     if (ch->r_io[reg].res) {
1019cf4fe2eSAlexander Motin 	ATA_IDX_OUTL(ch, reg, val);
1029cf4fe2eSAlexander Motin 	return (0);
1039cf4fe2eSAlexander Motin     }
104bda55b6aSAlexander Motin     return (-1);
1059cf4fe2eSAlexander Motin }
1069cf4fe2eSAlexander Motin 
10713014ca0SSøren Schmidt static int
ata_sata_connect(struct ata_channel * ch,int port,int quick)108bda55b6aSAlexander Motin ata_sata_connect(struct ata_channel *ch, int port, int quick)
10913014ca0SSøren Schmidt {
11013014ca0SSøren Schmidt     u_int32_t status;
111bda55b6aSAlexander Motin     int timeout, t;
11213014ca0SSøren Schmidt 
11313014ca0SSøren Schmidt     /* wait up to 1 second for "connect well" */
114bda55b6aSAlexander Motin     timeout = (quick == 2) ? 0 : 100;
115bda55b6aSAlexander Motin     t = 0;
116bda55b6aSAlexander Motin     while (1) {
1179cf4fe2eSAlexander Motin 	if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status))
1189cf4fe2eSAlexander Motin 	    return (0);
119bda55b6aSAlexander Motin 	if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
120bda55b6aSAlexander Motin 	    ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
121bda55b6aSAlexander Motin 	    ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE))
122bda55b6aSAlexander Motin 	    break;
123bda55b6aSAlexander Motin 	if (++t > timeout)
12413014ca0SSøren Schmidt 	    break;
12513014ca0SSøren Schmidt 	ata_udelay(10000);
12613014ca0SSøren Schmidt     }
1279cf4fe2eSAlexander Motin     if (bootverbose) {
128bda55b6aSAlexander Motin 	if (t > timeout) {
1299cf4fe2eSAlexander Motin 	    if (port < 0) {
1309cf4fe2eSAlexander Motin 		device_printf(ch->dev, "SATA connect timeout status=%08x\n",
1319cf4fe2eSAlexander Motin 		    status);
1329cf4fe2eSAlexander Motin 	    } else {
1339cf4fe2eSAlexander Motin 		device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n",
1349cf4fe2eSAlexander Motin 		    port, status);
1359cf4fe2eSAlexander Motin 	    }
136bda55b6aSAlexander Motin 	} else if (port < 0) {
1379cf4fe2eSAlexander Motin 	    device_printf(ch->dev, "SATA connect time=%dms status=%08x\n",
138bda55b6aSAlexander Motin 		t * 10, status);
1399cf4fe2eSAlexander Motin 	} else {
1409cf4fe2eSAlexander Motin 	    device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n",
141bda55b6aSAlexander Motin 		port, t * 10, status);
1429cf4fe2eSAlexander Motin 	}
1439cf4fe2eSAlexander Motin     }
14413014ca0SSøren Schmidt 
14513014ca0SSøren Schmidt     /* clear SATA error register */
1469cf4fe2eSAlexander Motin     ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);
14713014ca0SSøren Schmidt 
148bda55b6aSAlexander Motin     return ((t > timeout) ? 0 : 1);
14913014ca0SSøren Schmidt }
15013014ca0SSøren Schmidt 
15113014ca0SSøren Schmidt int
ata_sata_phy_reset(device_t dev,int port,int quick)1529cf4fe2eSAlexander Motin ata_sata_phy_reset(device_t dev, int port, int quick)
15313014ca0SSøren Schmidt {
15413014ca0SSøren Schmidt     struct ata_channel *ch = device_get_softc(dev);
1559c87d811SAlexander Motin     int loop, retry, sata_rev;
1569c87d811SAlexander Motin     uint32_t val, val1;
1579c87d811SAlexander Motin 
1589c87d811SAlexander Motin     sata_rev = ch->user[port < 0 ? 0 : port].revision;
1599c87d811SAlexander Motin     if (sata_rev > 0)
1609c87d811SAlexander Motin 	quick = 0;
16113014ca0SSøren Schmidt 
1629cf4fe2eSAlexander Motin     if (quick) {
1639cf4fe2eSAlexander Motin 	if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
1649cf4fe2eSAlexander Motin 	    return (0);
1655c2a4ae2SAlexander Motin 	if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) {
1665c2a4ae2SAlexander Motin 	    ata_sata_scr_write(ch, port, ATA_SCONTROL,
1675c2a4ae2SAlexander Motin 		ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 :
1685c2a4ae2SAlexander Motin 		ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER));
169bda55b6aSAlexander Motin 	    return ata_sata_connect(ch, port, quick);
1709cf4fe2eSAlexander Motin 	}
1715c2a4ae2SAlexander Motin     }
17213014ca0SSøren Schmidt 
1739cf4fe2eSAlexander Motin     if (bootverbose) {
1749cf4fe2eSAlexander Motin 	if (port < 0) {
1750eac2d6bSAlexander Motin 	    device_printf(dev, "hard reset ...\n");
1769cf4fe2eSAlexander Motin 	} else {
1770eac2d6bSAlexander Motin 	    device_printf(dev, "p%d: hard reset ...\n", port);
1789cf4fe2eSAlexander Motin 	}
1799cf4fe2eSAlexander Motin     }
1809c87d811SAlexander Motin     if (sata_rev == 1)
1819c87d811SAlexander Motin 	val1 = ATA_SC_SPD_SPEED_GEN1;
1829c87d811SAlexander Motin     else if (sata_rev == 2)
1839c87d811SAlexander Motin 	val1 = ATA_SC_SPD_SPEED_GEN2;
1849c87d811SAlexander Motin     else if (sata_rev == 3)
1859c87d811SAlexander Motin 	val1 = ATA_SC_SPD_SPEED_GEN3;
1869c87d811SAlexander Motin     else
1879c87d811SAlexander Motin 	val1 = 0;
18813014ca0SSøren Schmidt     for (retry = 0; retry < 10; retry++) {
18913014ca0SSøren Schmidt 	for (loop = 0; loop < 10; loop++) {
1909c87d811SAlexander Motin 	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET |
1919c87d811SAlexander Motin 		    val1 | ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))
1920eac2d6bSAlexander Motin 		goto fail;
19313014ca0SSøren Schmidt 	    ata_udelay(100);
1949cf4fe2eSAlexander Motin 	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
1950eac2d6bSAlexander Motin 		goto fail;
1969cf4fe2eSAlexander Motin 	    if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
19713014ca0SSøren Schmidt 		break;
19813014ca0SSøren Schmidt 	}
19913014ca0SSøren Schmidt 	ata_udelay(5000);
20013014ca0SSøren Schmidt 	for (loop = 0; loop < 10; loop++) {
2019cf4fe2eSAlexander Motin 	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
2029c87d811SAlexander Motin 		    ATA_SC_DET_IDLE | val1 | ((ch->pm_level > 0) ? 0 :
2034c10f2e6SAlexander Motin 		    ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)))
2040eac2d6bSAlexander Motin 		goto fail;
20513014ca0SSøren Schmidt 	    ata_udelay(100);
2069cf4fe2eSAlexander Motin 	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
2070eac2d6bSAlexander Motin 		goto fail;
2089cf4fe2eSAlexander Motin 	    if ((val & ATA_SC_DET_MASK) == 0)
209bda55b6aSAlexander Motin 		return ata_sata_connect(ch, port, 0);
21013014ca0SSøren Schmidt 	}
21113014ca0SSøren Schmidt     }
2120eac2d6bSAlexander Motin fail:
2130eac2d6bSAlexander Motin     /* Clear SATA error register. */
2140eac2d6bSAlexander Motin     ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);
2150eac2d6bSAlexander Motin 
2160eac2d6bSAlexander Motin     if (bootverbose) {
2170eac2d6bSAlexander Motin 	if (port < 0) {
2180eac2d6bSAlexander Motin 	    device_printf(dev, "hard reset failed\n");
2190eac2d6bSAlexander Motin 	} else {
2200eac2d6bSAlexander Motin 	    device_printf(dev, "p%d: hard reset failed\n", port);
2210eac2d6bSAlexander Motin 	}
2220eac2d6bSAlexander Motin     }
2230eac2d6bSAlexander Motin     return (0);
22413014ca0SSøren Schmidt }
22513014ca0SSøren Schmidt 
226066f913aSAlexander Motin int
ata_sata_setmode(device_t dev,int target,int mode)227066f913aSAlexander Motin ata_sata_setmode(device_t dev, int target, int mode)
22813014ca0SSøren Schmidt {
22913014ca0SSøren Schmidt 
230066f913aSAlexander Motin 	return (min(mode, ATA_UDMA5));
23113014ca0SSøren Schmidt }
232066f913aSAlexander Motin 
233066f913aSAlexander Motin int
ata_sata_getrev(device_t dev,int target)234066f913aSAlexander Motin ata_sata_getrev(device_t dev, int target)
235066f913aSAlexander Motin {
236066f913aSAlexander Motin 	struct ata_channel *ch = device_get_softc(dev);
237066f913aSAlexander Motin 
238066f913aSAlexander Motin 	if (ch->r_io[ATA_SSTATUS].res)
239066f913aSAlexander Motin 		return ((ATA_IDX_INL(ch, ATA_SSTATUS) & 0x0f0) >> 4);
2406a5d28b9SAlexander Motin 	return (0xff);
24113014ca0SSøren Schmidt }
24213014ca0SSøren Schmidt 
24313014ca0SSøren Schmidt int
ata_request2fis_h2d(struct ata_request * request,u_int8_t * fis)24413014ca0SSøren Schmidt ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
24513014ca0SSøren Schmidt {
24613014ca0SSøren Schmidt 
24713014ca0SSøren Schmidt     if (request->flags & ATA_R_ATAPI) {
24813014ca0SSøren Schmidt 	fis[0] = 0x27;  		/* host to device */
249ebbb35baSAlexander Motin 	fis[1] = 0x80 | (request->unit & 0x0f);
25013014ca0SSøren Schmidt 	fis[2] = ATA_PACKET_CMD;
25113014ca0SSøren Schmidt 	if (request->flags & (ATA_R_READ | ATA_R_WRITE))
25213014ca0SSøren Schmidt 	    fis[3] = ATA_F_DMA;
25313014ca0SSøren Schmidt 	else {
25413014ca0SSøren Schmidt 	    fis[5] = request->transfersize;
25513014ca0SSøren Schmidt 	    fis[6] = request->transfersize >> 8;
25613014ca0SSøren Schmidt 	}
25713014ca0SSøren Schmidt 	fis[7] = ATA_D_LBA;
25813014ca0SSøren Schmidt 	fis[15] = ATA_A_4BIT;
25913014ca0SSøren Schmidt 	return 20;
26013014ca0SSøren Schmidt     }
26113014ca0SSøren Schmidt     else {
26213014ca0SSøren Schmidt 	fis[0] = 0x27;			/* host to device */
263ebbb35baSAlexander Motin 	fis[1] = 0x80 | (request->unit & 0x0f);
26413014ca0SSøren Schmidt 	fis[2] = request->u.ata.command;
26513014ca0SSøren Schmidt 	fis[3] = request->u.ata.feature;
26613014ca0SSøren Schmidt 	fis[4] = request->u.ata.lba;
26713014ca0SSøren Schmidt 	fis[5] = request->u.ata.lba >> 8;
26813014ca0SSøren Schmidt 	fis[6] = request->u.ata.lba >> 16;
26913014ca0SSøren Schmidt 	fis[7] = ATA_D_LBA;
270ebbb35baSAlexander Motin 	if (!(request->flags & ATA_R_48BIT))
27113014ca0SSøren Schmidt 	    fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f));
27213014ca0SSøren Schmidt 	fis[8] = request->u.ata.lba >> 24;
27313014ca0SSøren Schmidt 	fis[9] = request->u.ata.lba >> 32;
27413014ca0SSøren Schmidt 	fis[10] = request->u.ata.lba >> 40;
27513014ca0SSøren Schmidt 	fis[11] = request->u.ata.feature >> 8;
27613014ca0SSøren Schmidt 	fis[12] = request->u.ata.count;
27713014ca0SSøren Schmidt 	fis[13] = request->u.ata.count >> 8;
27813014ca0SSøren Schmidt 	fis[15] = ATA_A_4BIT;
27913014ca0SSøren Schmidt 	return 20;
28013014ca0SSøren Schmidt     }
28113014ca0SSøren Schmidt     return 0;
28213014ca0SSøren Schmidt }
28313014ca0SSøren Schmidt 
28413014ca0SSøren Schmidt void
ata_pm_identify(device_t dev)28513014ca0SSøren Schmidt ata_pm_identify(device_t dev)
28613014ca0SSøren Schmidt {
28713014ca0SSøren Schmidt     struct ata_channel *ch = device_get_softc(dev);
28813014ca0SSøren Schmidt     u_int32_t pm_chipid, pm_revision, pm_ports;
28913014ca0SSøren Schmidt     int port;
29013014ca0SSøren Schmidt 
29113014ca0SSøren Schmidt     /* get PM vendor & product data */
29213014ca0SSøren Schmidt     if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) {
29313014ca0SSøren Schmidt 	device_printf(dev, "error getting PM vendor data\n");
29413014ca0SSøren Schmidt 	return;
29513014ca0SSøren Schmidt     }
29613014ca0SSøren Schmidt 
29713014ca0SSøren Schmidt     /* get PM revision data */
29813014ca0SSøren Schmidt     if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) {
299453130d9SPedro F. Giffuni 	device_printf(dev, "error getting PM revision data\n");
30013014ca0SSøren Schmidt 	return;
30113014ca0SSøren Schmidt     }
30213014ca0SSøren Schmidt 
30313014ca0SSøren Schmidt     /* get number of HW ports on the PM */
30413014ca0SSøren Schmidt     if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) {
30513014ca0SSøren Schmidt 	device_printf(dev, "error getting PM port info\n");
30613014ca0SSøren Schmidt 	return;
30713014ca0SSøren Schmidt     }
30813014ca0SSøren Schmidt     pm_ports &= 0x0000000f;
30913014ca0SSøren Schmidt 
31013014ca0SSøren Schmidt     /* chip specific quirks */
31113014ca0SSøren Schmidt     switch (pm_chipid) {
31213014ca0SSøren Schmidt     case 0x37261095:
3139cf4fe2eSAlexander Motin 	/* This PM declares 6 ports, while only 5 of them are real.
3149cf4fe2eSAlexander Motin 	 * Port 5 is enclosure management bridge port, which has implementation
3159cf4fe2eSAlexander Motin 	 * problems, causing probe faults. Hide it for now. */
3169cf4fe2eSAlexander Motin 	device_printf(dev, "SiI 3726 (rev=%x) Port Multiplier with %d (5) ports\n",
31713014ca0SSøren Schmidt 		      pm_revision, pm_ports);
3189cf4fe2eSAlexander Motin 	pm_ports = 5;
3199cf4fe2eSAlexander Motin 	break;
3209cf4fe2eSAlexander Motin 
3219cf4fe2eSAlexander Motin     case 0x47261095:
3229cf4fe2eSAlexander Motin 	/* This PM declares 7 ports, while only 5 of them are real.
3239cf4fe2eSAlexander Motin 	 * Port 5 is some fake "Config  Disk" with 640 sectors size,
3249cf4fe2eSAlexander Motin 	 * port 6 is enclosure management bridge port.
3259cf4fe2eSAlexander Motin 	 * Both fake ports has implementation problems, causing
3269cf4fe2eSAlexander Motin 	 * probe faults. Hide them for now. */
3279cf4fe2eSAlexander Motin 	device_printf(dev, "SiI 4726 (rev=%x) Port Multiplier with %d (5) ports\n",
3289cf4fe2eSAlexander Motin 		      pm_revision, pm_ports);
3299cf4fe2eSAlexander Motin 	pm_ports = 5;
33013014ca0SSøren Schmidt 	break;
33113014ca0SSøren Schmidt 
33213014ca0SSøren Schmidt     default:
3339cf4fe2eSAlexander Motin 	device_printf(dev, "Port Multiplier (id=%08x rev=%x) with %d ports\n",
33413014ca0SSøren Schmidt 		      pm_chipid, pm_revision, pm_ports);
33513014ca0SSøren Schmidt     }
33613014ca0SSøren Schmidt 
33713014ca0SSøren Schmidt     /* reset all ports and register if anything connected */
33813014ca0SSøren Schmidt     for (port=0; port < pm_ports; port++) {
3399cf4fe2eSAlexander Motin 	u_int32_t signature;
34013014ca0SSøren Schmidt 
3419cf4fe2eSAlexander Motin 	if (!ata_sata_phy_reset(dev, port, 1))
34213014ca0SSøren Schmidt 	    continue;
34313014ca0SSøren Schmidt 
3449cf4fe2eSAlexander Motin 	/*
3459cf4fe2eSAlexander Motin 	 * XXX: I have no idea how to properly wait for PMP port hardreset
3469cf4fe2eSAlexander Motin 	 * completion. Without this delay soft reset does not completes
3479cf4fe2eSAlexander Motin 	 * successfully.
3489cf4fe2eSAlexander Motin 	 */
3499cf4fe2eSAlexander Motin 	DELAY(1000000);
35013014ca0SSøren Schmidt 
35113014ca0SSøren Schmidt 	signature = ch->hw.softreset(dev, port);
35213014ca0SSøren Schmidt 
35313014ca0SSøren Schmidt 	if (bootverbose)
35413014ca0SSøren Schmidt 	    device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature);
35513014ca0SSøren Schmidt 
35613014ca0SSøren Schmidt 	/* figure out whats there */
357e412a8c3SAlexander Motin 	switch (signature >> 16) {
358e412a8c3SAlexander Motin 	case 0x0000:
35913014ca0SSøren Schmidt 	    ch->devices |= (ATA_ATA_MASTER << port);
36013014ca0SSøren Schmidt 	    continue;
361e412a8c3SAlexander Motin 	case 0xeb14:
36213014ca0SSøren Schmidt 	    ch->devices |= (ATA_ATAPI_MASTER << port);
36313014ca0SSøren Schmidt 	    continue;
36413014ca0SSøren Schmidt 	}
36513014ca0SSøren Schmidt     }
36613014ca0SSøren Schmidt }
367