Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Jun 2009 20:54:32 GMT
From:      Alexander Motin <mav@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 164293 for review
Message-ID:  <200906132054.n5DKsWMY075017@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=164293

Change 164293 by mav@mav_mavbook on 2009/06/13 20:53:49

	Add basic SATA Port Multiplier support.

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_all.c#9 edit
.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_all.h#9 edit
.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#16 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_ccb.h#21 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#25 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_all.c#9 (text+ko) ====

@@ -133,11 +133,42 @@
 	ataio->cmd.features_exp = sector_count >> 8;
 }
 
-void	ata_reset_cmd(struct ccb_ataio *ataio)
+void
+ata_reset_cmd(struct ccb_ataio *ataio)
 {
 	bzero(&ataio->cmd, sizeof(ataio->cmd));
 	ataio->cmd.flags = CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT;
 	ataio->cmd.control = 0x04;
 }
 
+void
+ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port)
+{
+	bzero(&ataio->cmd, sizeof(ataio->cmd));
+	ataio->cmd.flags = CAM_ATAIO_48BIT | CAM_ATAIO_NEEDRESULT;
+	ataio->cmd.command = ATA_READ_PM;
+	ataio->cmd.features = reg;
+	ataio->cmd.features_exp = reg >> 8;
+	ataio->cmd.device = port & 0x0f;
+}
+
+void
+ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint64_t val)
+{
+	bzero(&ataio->cmd, sizeof(ataio->cmd));
+	ataio->cmd.flags = CAM_ATAIO_48BIT | CAM_ATAIO_NEEDRESULT;
+	ataio->cmd.command = ATA_WRITE_PM;
+	ataio->cmd.features = reg;
+	ataio->cmd.lba_low = val >> 8;
+	ataio->cmd.lba_mid = val >> 16;
+	ataio->cmd.lba_high = val >> 24;
+	ataio->cmd.device = port & 0x0f;
+	ataio->cmd.lba_low_exp = val >> 40;
+	ataio->cmd.lba_mid_exp = val >> 48;
+	ataio->cmd.lba_high_exp = val >> 56;
+	ataio->cmd.features_exp = reg >> 8;
+	ataio->cmd.sector_count = val;
+	ataio->cmd.sector_count_exp = val >> 32;
+}
+
 #endif /* _KERNEL */

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_all.h#9 (text+ko) ====

@@ -87,5 +87,7 @@
 void	ata_ncq_cmd(struct ccb_ataio *ataio, uint8_t cmd,
     uint64_t lba, uint16_t sector_count);
 void	ata_reset_cmd(struct ccb_ataio *ataio);
+void	ata_pm_read_cmd(struct ccb_ataio *ataio, int reg, int port);
+void	ata_pm_write_cmd(struct ccb_ataio *ataio, int reg, int port, uint64_t val);
 
 #endif

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#16 (text+ko) ====

@@ -95,6 +95,13 @@
 	PROBE_IDENTIFY,
 	PROBE_INQUIRY,
 	PROBE_FULL_INQUIRY,
+	PROBE_PM_PID,
+	PROBE_PM_PRV,
+	PROBE_PM_PORTS,
+	PROBE_PM_RESET,
+	PROBE_PM_CONNECT,
+	PROBE_PM_CHECK,
+	PROBE_PM_CLEAR,
 	PROBE_INVALID
 } probe_action;
 
@@ -103,6 +110,13 @@
 	"PROBE_IDENTIFY",
 	"PROBE_INQUIRY",
 	"PROBE_FULL_INQUIRY",
+	"PROBE_PM_PID",
+	"PROBE_PM_PRV",
+	"PROBE_PM_PORTS",
+	"PROBE_PM_RESET",
+	"PROBE_PM_CONNECT",
+	"PROBE_PM_CHECK",
+	"PROBE_PM_CLEAR",
 	"PROBE_INVALID"
 };
 
@@ -126,6 +140,12 @@
 	union ccb	saved_ccb;
 	probe_flags	flags;
 	u_int8_t	digest[16];
+	uint32_t	pm_pid;
+	uint32_t	pm_prv;
+	int		pm_ports;
+	int		pm_step;
+	int		pm_try;
+	int		pm_found;
 	struct cam_periph *periph;
 } probe_softc;
 
@@ -329,21 +349,20 @@
 	switch (softc->action) {
 	case PROBE_RESET:
 		cam_fill_ataio(ataio,
-		      4,
+		      1,
 		      probedone,
 		      /*flags*/CAM_DIR_NONE,
 		      MSG_SIMPLE_Q_TAG,
 		      /*data_ptr*/NULL,
 		      /*dxfer_len*/0,
-		      30 * 1000);
+		      10 * 1000);
 		ata_reset_cmd(ataio);
 		break;
 	case PROBE_IDENTIFY:
 	{
-		struct ata_params *ident_buf;
+		struct ata_params *ident_buf =
+		    &periph->path->device->ident_data;
 
-		ident_buf = &periph->path->device->ident_data;
-
 		if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
 			/* Prepare check that it is the same device. */
 			MD5_CTX context;
@@ -360,16 +379,14 @@
 			    sizeof(ident_buf->serial));
 			MD5Final(softc->digest, &context);
 		}
-
 		cam_fill_ataio(ataio,
-		      4,
+		      1,
 		      probedone,
 		      /*flags*/CAM_DIR_IN,
 		      MSG_SIMPLE_Q_TAG,
 		      /*data_ptr*/(u_int8_t *)ident_buf,
 		      /*dxfer_len*/sizeof(struct ata_params),
 		      30 * 1000);
-
 		if (periph->path->device->protocol == PROTO_ATA)
 			ata_36bit_cmd(ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
 		else
@@ -380,15 +397,13 @@
 	case PROBE_FULL_INQUIRY:
 	{
 		u_int inquiry_len;
-		struct scsi_inquiry_data *inq_buf;
-
-		inq_buf = &periph->path->device->inq_data;
+		struct scsi_inquiry_data *inq_buf =
+		    &periph->path->device->inq_data;
 
 		if (softc->action == PROBE_INQUIRY)
 			inquiry_len = SHORT_INQUIRY_LENGTH;
 		else
 			inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf);
-
 		/*
 		 * Some parallel SCSI devices fail to send an
 		 * ignore wide residue message when dealing with
@@ -396,7 +411,6 @@
 		 * safe.
 		 */
 		inquiry_len = roundup2(inquiry_len, 2);
-
 		scsi_inquiry(csio,
 			     /*retries*/4,
 			     probedone,
@@ -409,6 +423,83 @@
 			     /*timeout*/60 * 1000);
 		break;
 	}
+	case PROBE_PM_PID:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_read_cmd(ataio, 0, 15);
+		break;
+	case PROBE_PM_PRV:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_read_cmd(ataio, 1, 15);
+		break;
+	case PROBE_PM_PORTS:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_read_cmd(ataio, 2, 15);
+		break;
+	case PROBE_PM_RESET:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_write_cmd(ataio, 2, softc->pm_step, 1);
+		break;
+	case PROBE_PM_CONNECT:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_write_cmd(ataio, 2, softc->pm_step, 0);
+		break;
+	case PROBE_PM_CHECK:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_read_cmd(ataio, 0, softc->pm_step);
+		break;
+	case PROBE_PM_CLEAR:
+		cam_fill_ataio(ataio,
+		      1,
+		      probedone,
+		      /*flags*/CAM_DIR_NONE,
+		      MSG_SIMPLE_Q_TAG,
+		      /*data_ptr*/NULL,
+		      /*dxfer_len*/0,
+		      10 * 1000);
+		ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF);
+		break;
 	case PROBE_INVALID:
 		CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
 		    ("probestart: invalid action state\n"));
@@ -546,6 +637,7 @@
 	probe_softc *softc;
 	struct cam_path *path;
 	u_int32_t  priority;
+	int found = 0;
 
 	CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n"));
 
@@ -556,15 +648,27 @@
 	switch (softc->action) {
 	case PROBE_RESET:
 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
-			printf("SIGNATURE: %02x%02x%02x%02x\n",
-			    done_ccb->ataio.res.lba_high, done_ccb->ataio.res.lba_mid,
-			    done_ccb->ataio.res.lba_low, done_ccb->ataio.res.sector_count);
-			if (done_ccb->ataio.res.lba_high == 0xeb &&
-			    done_ccb->ataio.res.lba_mid == 0x14)
+			int sign = (done_ccb->ataio.res.lba_high << 8) +
+			    done_ccb->ataio.res.lba_mid;
+			printf("SIGNATURE: %04x\n", sign);
+			if (sign == 0x0000 &&
+			    done_ccb->ccb_h.target_id != 15) {
+				path->device->protocol = PROTO_ATA;
+				PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
+			} else if (sign == 0x9669 &&
+			    done_ccb->ccb_h.target_id == 15) {
+				path->device->protocol = PROTO_SATAPM;
+				PROBE_SET_ACTION(softc, PROBE_PM_PID);
+			} else if (sign == 0xeb14 &&
+			    done_ccb->ccb_h.target_id != 15) {
 				path->device->protocol = PROTO_SCSI;
-			else
-				path->device->protocol = PROTO_ATA;
-			PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
+				PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
+			} else {
+				xpt_print(path,
+				    "Unexpected signature 0x%04x\n", sign);
+				xpt_release_ccb(done_ccb);
+				break;
+			}
 			xpt_release_ccb(done_ccb);
 			xpt_schedule(periph, priority);
 			return;
@@ -654,12 +758,7 @@
 			path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID;
 
 			scsi_find_quirk(path->device);
-
 			ata_device_transport(path);
-//			if (INQ_DATA_TQ_ENABLED(inq_buf))
-//				PROBE_SET_ACTION(softc, PROBE_MODE_SENSE);
-//			else
-//				PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0);
 
 //			if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) {
 			if (path->device->protocol == PROTO_ATA) {
@@ -779,6 +878,209 @@
 		xpt_release_ccb(done_ccb);
 		break;
 	}
+	case PROBE_PM_PID:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_pid = (done_ccb->ataio.res.lba_high << 24) +
+			    (done_ccb->ataio.res.lba_mid << 16) +
+			    (done_ccb->ataio.res.lba_low << 8) +
+			    done_ccb->ataio.res.sector_count;
+			printf("PM Product ID: %08x\n", softc->pm_pid);
+			PROBE_SET_ACTION(softc, PROBE_PM_PRV);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_PRV:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
+			    (done_ccb->ataio.res.lba_mid << 16) +
+			    (done_ccb->ataio.res.lba_low << 8) +
+			    done_ccb->ataio.res.sector_count;
+			printf("PM Revision: %08x\n", softc->pm_prv);
+			PROBE_SET_ACTION(softc, PROBE_PM_PORTS);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_PORTS:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) +
+			    (done_ccb->ataio.res.lba_mid << 16) +
+			    (done_ccb->ataio.res.lba_low << 8) +
+			    done_ccb->ataio.res.sector_count;
+			/* This PM declares 6 ports, while only 5 of them are real.
+			 * Port 5 is enclosure management bridge port, which has implementation
+			 * problems, causing probe faults. Hide it for now. */
+			if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6)
+				softc->pm_ports = 5;
+			/* This PM declares 7 ports, while only 5 of them are real.
+			 * Port 5 is some fake "Config  Disk" with 640 sectors size,
+			 * port 6 is enclosure management bridge port.
+			 * Both fake ports has implementation problems, causing
+			 * probe faults. Hide them for now. */
+			if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7)
+				softc->pm_ports = 5;
+			printf("PM ports: %d\n", softc->pm_ports);
+			PROBE_SET_ACTION(softc, PROBE_PM_RESET);
+			xpt_release_ccb(done_ccb);
+			xpt_schedule(periph, priority);
+			return;
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_RESET:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_step++;
+			if (softc->pm_step < softc->pm_ports) {
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			} else {
+				softc->pm_step = 0;
+				DELAY(5000);
+				PROBE_SET_ACTION(softc, PROBE_PM_CONNECT);
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			}
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_CONNECT:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_step++;
+			if (softc->pm_step < softc->pm_ports) {
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			} else {
+				softc->pm_step = 0;
+				softc->pm_found = 0x8000;
+				PROBE_SET_ACTION(softc, PROBE_PM_CHECK);
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			}
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_CHECK:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			int res = (done_ccb->ataio.res.lba_high << 24) +
+			    (done_ccb->ataio.res.lba_mid << 16) +
+			    (done_ccb->ataio.res.lba_low << 8) +
+			    done_ccb->ataio.res.sector_count;
+			if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) {
+				printf("PM found: %d - %08x\n", softc->pm_step, res);
+				softc->pm_found |= (1 << softc->pm_step);
+				softc->pm_step++;
+			} else {
+				if (softc->pm_try < 50) {
+					DELAY(10000);
+					softc->pm_try++;
+				} else
+					softc->pm_step++;
+			}
+			if (softc->pm_step < softc->pm_ports) {
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			} else {
+				softc->pm_step = 0;
+				PROBE_SET_ACTION(softc, PROBE_PM_CLEAR);
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			}
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
+	case PROBE_PM_CLEAR:
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+			softc->pm_step++;
+			if (softc->pm_step < softc->pm_ports) {
+				xpt_release_ccb(done_ccb);
+				xpt_schedule(periph, priority);
+				return;
+			}
+			found = softc->pm_found;
+		} else if (cam_periph_error(done_ccb, 0,
+					    done_ccb->ccb_h.target_lun > 0
+					    ? SF_RETRY_UA|SF_QUIET_IR
+					    : SF_RETRY_UA,
+					    &softc->saved_ccb) == ERESTART) {
+			return;
+		} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+			/* Don't wedge the queue */
+			xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+					 /*run_queue*/TRUE);
+		}
+		xpt_release_ccb(done_ccb);
+		break;
 	case PROBE_INVALID:
 		CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO,
 		    ("probedone: invalid action state\n"));
@@ -788,6 +1090,7 @@
 	done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
 	TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
 	done_ccb->ccb_h.status = CAM_REQ_CMP;
+	done_ccb->ccb_h.ppriv_field1 = found;
 	xpt_done(done_ccb);
 	if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
 		cam_periph_invalidate(periph);
@@ -828,6 +1131,7 @@
 	union	ccb *request_ccb;
 	struct 	ccb_pathinq *cpi;
 	int	counter;
+	int	found;
 } ata_scan_bus_info;
 
 /*
@@ -838,17 +1142,15 @@
 static void
 ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
 {
+	struct	cam_path *path;
+	ata_scan_bus_info *scan_info;
+	union	ccb *work_ccb;
+	cam_status status;
+
 	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
 		  ("xpt_scan_bus\n"));
 	switch (request_ccb->ccb_h.func_code) {
 	case XPT_SCAN_BUS:
-	{
-		ata_scan_bus_info *scan_info;
-		union	ccb *work_ccb;
-		struct	cam_path *path;
-		u_int	i;
-		u_int	max_target;
-
 		/* Find out the characteristics of the bus */
 		work_ccb = xpt_alloc_ccb_nowait();
 		if (work_ccb == NULL) {
@@ -877,88 +1179,36 @@
 		}
 		scan_info->request_ccb = request_ccb;
 		scan_info->cpi = &work_ccb->cpi;
+		scan_info->found = 0x8001;
 
-		/* Cache on our stack so we can work asynchronously */
-		max_target = scan_info->cpi->max_target;
+		/* If PM supported, probe it first. */
+		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
+			scan_info->counter = 15;
 
-		/*
-		 * We can scan all targets in parallel, or do it sequentially.
-		 */
-		if (scan_info->cpi->hba_misc & PIM_SEQSCAN) {
-			max_target = 0;
-			scan_info->counter = 0;
-		} else {
-			scan_info->counter = scan_info->cpi->max_target + 1;
+		work_ccb = xpt_alloc_ccb_nowait();
+		if (work_ccb == NULL) {
+			free(scan_info, M_CAMXPT);
+			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			xpt_done(request_ccb);
+			break;
 		}
-
-		for (i = 0; i <= max_target; i++) {
-			cam_status status;
-
-			status = xpt_create_path(&path, xpt_periph,
-						 request_ccb->ccb_h.path_id,
-						 i, 0);
-			if (status != CAM_REQ_CMP) {
-				printf("xpt_scan_bus: xpt_create_path failed"
-				       " with status %#x, bus scan halted\n",
-				       status);
-				free(scan_info, M_CAMXPT);
-				request_ccb->ccb_h.status = status;
-				xpt_free_ccb(work_ccb);
-				xpt_done(request_ccb);
-				break;
-			}
-			work_ccb = xpt_alloc_ccb_nowait();
-			if (work_ccb == NULL) {
-				free(scan_info, M_CAMXPT);
-				xpt_free_path(path);
-				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
-				xpt_done(request_ccb);
-				break;
-			}
-			xpt_setup_ccb(&work_ccb->ccb_h, path,
-				      request_ccb->ccb_h.pinfo.priority);
-			work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
-			work_ccb->ccb_h.cbfcnp = ata_scan_bus;
-			work_ccb->ccb_h.ppriv_ptr0 = scan_info;
-			work_ccb->crcn.flags = request_ccb->crcn.flags;
-			xpt_action(work_ccb);
-		}
-		break;
-	}
+		goto scan_next;
 	case XPT_SCAN_LUN:
-	{
-		cam_status status;
-		struct cam_path *path;
-		ata_scan_bus_info *scan_info;
-		path_id_t path_id;
-		target_id_t target_id;
-		int done;
-
+		work_ccb = request_ccb;
 		/* Reuse the same CCB to query if a device was really found */
-		scan_info = (ata_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0;
-		path_id = request_ccb->ccb_h.path_id;
-		target_id = request_ccb->ccb_h.target_id;
+		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
 
 		/*
 		 * Free the current request path- we're done with it.
 		 */
-		xpt_free_path(request_ccb->ccb_h.path);
-
-		done = 0;
-		if (scan_info->cpi->hba_misc & PIM_SEQSCAN) {
-			scan_info->counter++;
-			if (scan_info->counter >=
-			    scan_info->cpi->max_target+1) {
-				done = 1;
-			}
-		} else {
-			scan_info->counter--;
-			if (scan_info->counter == 0) {
-				done = 1;
-			}
-		}
-		if (done) {
-			xpt_free_ccb(request_ccb);
+		xpt_free_path(work_ccb->ccb_h.path);
+		if (scan_info->counter == 15)
+			scan_info->found = work_ccb->ccb_h.ppriv_field1;
+take_next:
+		/* Take next device. Wrap from 15 (PM) to 0. */
+		scan_info->counter = (scan_info->counter + 1 ) & 0x0f;
+		if (scan_info->counter >= scan_info->cpi->max_target+1) {
+			xpt_free_ccb(work_ccb);
 			xpt_free_ccb((union ccb *)scan_info->cpi);
 			request_ccb = scan_info->request_ccb;
 			free(scan_info, M_CAMXPT);
@@ -966,18 +1216,15 @@
 			xpt_done(request_ccb);
 			break;
 		}
-
-		if ((scan_info->cpi->hba_misc & PIM_SEQSCAN) == 0)
-			break;
-
+scan_next:
 		status = xpt_create_path(&path, xpt_periph,
 		    scan_info->request_ccb->ccb_h.path_id,
 		    scan_info->counter, 0);
 		if (status != CAM_REQ_CMP) {
 			printf("xpt_scan_bus: xpt_create_path failed"
 			    " with status %#x, bus scan halted\n",
-		       	    status);
-			xpt_free_ccb(request_ccb);
+			    status);
+			xpt_free_ccb(work_ccb);
 			xpt_free_ccb((union ccb *)scan_info->cpi);
 			request_ccb = scan_info->request_ccb;
 			free(scan_info, M_CAMXPT);
@@ -985,16 +1232,18 @@
 			xpt_done(request_ccb);
 			break;
 		}
-		xpt_setup_ccb(&request_ccb->ccb_h, path,
-		    request_ccb->ccb_h.pinfo.priority);
-		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
-		request_ccb->ccb_h.cbfcnp = ata_scan_bus;
-		request_ccb->ccb_h.ppriv_ptr0 = scan_info;
-		request_ccb->crcn.flags =
-		    scan_info->request_ccb->crcn.flags;
-		xpt_action(request_ccb);
+		if ((scan_info->found & (1 << scan_info->counter)) == 0) {
+			xpt_async(AC_LOST_DEVICE, path, NULL);
+			goto take_next;
+		}
+		xpt_setup_ccb(&work_ccb->ccb_h, path,
+		    scan_info->request_ccb->ccb_h.pinfo.priority);
+		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
+		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
+		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
+		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
+		xpt_action(work_ccb);
 		break;
-	}
 	default:
 		break;
 	}

==== //depot/projects/scottl-camlock/src/sys/cam/cam_ccb.h#21 (text+ko) ====


==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#25 (text+ko) ====

@@ -1634,10 +1634,15 @@
 
 		cpi->version_num = 1; /* XXX??? */
 		cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
+		if (ch->caps & AHCI_CAP_SPM)
+			cpi->hba_inquiry |= PI_SATAPM;
 		cpi->target_sprt = 0;
 		cpi->hba_misc = PIM_SEQSCAN;
 		cpi->hba_eng_cnt = 0;
-		cpi->max_target = 0;
+		if (ch->caps & AHCI_CAP_SPM)
+			cpi->max_target = 14;
+		else
+			cpi->max_target = 0;
 		cpi->max_lun = 0;
 		cpi->initiator_id = 0;
 		cpi->bus_id = cam_sim_bus(sim);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906132054.n5DKsWMY075017>