summaryrefslogtreecommitdiffstats
path: root/sys/dev/ciss
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2003-02-05 08:43:46 +0000
committerps <ps@FreeBSD.org>2003-02-05 08:43:46 +0000
commit0eca408203af42b507f3bd31ee7949304aa8a26d (patch)
tree75fcd112d3b72019aa821398b5ceaabd92d11151 /sys/dev/ciss
parent79b6a6c38cc108fee126e8cceebeeb370c0cda6d (diff)
downloadFreeBSD-src-0eca408203af42b507f3bd31ee7949304aa8a26d.zip
FreeBSD-src-0eca408203af42b507f3bd31ee7949304aa8a26d.tar.gz
Properly get the drive geometry from the controller. This should
fix booting off of volumes > 255GB.
Diffstat (limited to 'sys/dev/ciss')
-rw-r--r--sys/dev/ciss/ciss.c102
-rw-r--r--sys/dev/ciss/cissreg.h15
-rw-r--r--sys/dev/ciss/cissvar.h1
3 files changed, 108 insertions, 10 deletions
diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c
index 342bed8..f2122b7 100644
--- a/sys/dev/ciss/ciss.c
+++ b/sys/dev/ciss/ciss.c
@@ -1011,6 +1011,67 @@ ciss_init_logical(struct ciss_softc *sc)
return(error);
}
+static int
+ciss_inquiry_logical(struct ciss_softc *sc, struct ciss_ldrive *ld)
+{
+ struct ciss_request *cr;
+ struct ciss_command *cc;
+ struct scsi_inquiry *inq;
+ int error;
+ int command_status;
+ int lun;
+
+ cr = NULL;
+ lun = ld->cl_address.logical.lun;
+
+ bzero(&ld->cl_geometry, sizeof(ld->cl_geometry));
+
+ if ((error = ciss_get_request(sc, &cr)) != 0)
+ goto out;
+
+ cc = CISS_FIND_COMMAND(cr);
+ cr->cr_data = &ld->cl_geometry;
+ cr->cr_length = sizeof(ld->cl_geometry);
+ cr->cr_flags = CISS_REQ_DATAIN;
+
+ cc->header.address.logical.mode = CISS_HDR_ADDRESS_MODE_LOGICAL;
+ cc->header.address.logical.lun = lun;
+ cc->cdb.cdb_length = 6;
+ cc->cdb.type = CISS_CDB_TYPE_COMMAND;
+ cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE;
+ cc->cdb.direction = CISS_CDB_DIRECTION_READ;
+ cc->cdb.timeout = 30;
+
+ inq = (struct scsi_inquiry *)&(cc->cdb.cdb[0]);
+ inq->opcode = INQUIRY;
+ inq->byte2 = SI_EVPD;
+ inq->page_code = CISS_VPD_LOGICAL_DRIVE_GEOMETRY;
+ inq->length = sizeof(ld->cl_geometry);
+
+ if ((error = ciss_synch_request(cr, 60 * 1000)) != 0) {
+ ciss_printf(sc, "error getting geometry (%d)\n", error);
+ goto out;
+ }
+
+ ciss_report_request(cr, &command_status, NULL);
+ switch(command_status) {
+ case CISS_CMD_STATUS_SUCCESS:
+ case CISS_CMD_STATUS_DATA_UNDERRUN:
+ break;
+ case CISS_CMD_STATUS_DATA_OVERRUN:
+ ciss_printf(sc, "WARNING: Data overrun\n");
+ break;
+ default:
+ ciss_printf(sc, "Error detecting logical drive geometry (%s)\n",
+ ciss_name_command_status(command_status));
+ break;
+ }
+
+out:
+ if (cr != NULL)
+ ciss_release_request(cr);
+ return(error);
+}
/************************************************************************
* Identify a logical drive, initialise state related to it.
*/
@@ -1071,6 +1132,12 @@ ciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld)
goto out;
/*
+ * Get the logical drive geometry.
+ */
+ if ((error = ciss_inquiry_logical(sc, ld)) != 0)
+ goto out;
+
+ /*
* Print the drive's basic characteristics.
*/
if (1/*bootverbose*/) {
@@ -2077,11 +2144,19 @@ ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
static void
ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
{
+ struct ciss_softc *sc;
+ struct ccb_scsiio *csio;
+ int target;
+
+ sc = cam_sim_softc(sim);
+ csio = (struct ccb_scsiio *)&ccb->csio;
+ target = csio->ccb_h.target_id;
+
switch (ccb->ccb_h.func_code) {
/* perform SCSI I/O */
case XPT_SCSI_IO:
- if (!ciss_cam_action_io(sim, (struct ccb_scsiio *)&ccb->csio))
+ if (!ciss_cam_action_io(sim, csio))
return;
break;
@@ -2089,20 +2164,27 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
case XPT_CALC_GEOMETRY:
{
struct ccb_calc_geometry *ccg = &ccb->ccg;
- u_int32_t secs_per_cylinder;
+ struct ciss_ldrive *ld = &sc->ciss_logical[target];
debug(1, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
/*
- * This is the default geometry; hopefully we will have
- * successfully talked to the 'disk' and obtained its private
- * settings.
+ * Use the cached geometry settings unless the fault tolerance
+ * is invalid.
*/
- ccg->heads = 255;
- ccg->secs_per_track = 32;
- secs_per_cylinder = ccg->heads * ccg->secs_per_track;
- ccg->cylinders = ccg->volume_size / secs_per_cylinder;
- ccb->ccb_h.status = CAM_REQ_CMP;
+ if (ld->cl_geometry.fault_tolerance == 0xFF) {
+ u_int32_t secs_per_cylinder;
+
+ ccg->heads = 255;
+ ccg->secs_per_track = 32;
+ secs_per_cylinder = ccg->heads * ccg->secs_per_track;
+ ccg->cylinders = ccg->volume_size / secs_per_cylinder;
+ } else {
+ ccg->heads = ld->cl_geometry.heads;
+ ccg->secs_per_track = ld->cl_geometry.sectors;
+ ccg->cylinders = ntohs(ld->cl_geometry.cylinders);
+ }
+ ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
diff --git a/sys/dev/ciss/cissreg.h b/sys/dev/ciss/cissreg.h
index 2e5e71e..c7844e9 100644
--- a/sys/dev/ciss/cissreg.h
+++ b/sys/dev/ciss/cissreg.h
@@ -169,6 +169,21 @@ struct ciss_lun_report
union ciss_device_address lun[0];
} __packed;
+#define CISS_VPD_LOGICAL_DRIVE_GEOMETRY 0xc1
+struct ciss_ldrive_geometry
+{
+ u_int8_t periph_qualifier:3;
+ u_int8_t periph_devtype:5;
+ u_int8_t page_code;
+ u_int8_t res1;
+ u_int8_t page_length;
+ u_int16_t cylinders; /* big-endian */
+ u_int8_t heads;
+ u_int8_t sectors;
+ u_int8_t fault_tolerance;
+ u_int8_t res2[3];
+} __attribute__ ((packed));
+
struct ciss_report_cdb
{
u_int8_t opcode;
diff --git a/sys/dev/ciss/cissvar.h b/sys/dev/ciss/cissvar.h
index 5baa136..4c102e0 100644
--- a/sys/dev/ciss/cissvar.h
+++ b/sys/dev/ciss/cissvar.h
@@ -158,6 +158,7 @@ struct ciss_ldrive
struct ciss_bmic_id_ldrive *cl_ldrive;
struct ciss_bmic_id_lstatus *cl_lstatus;
+ struct ciss_ldrive_geometry cl_geometry;
char cl_name[16]; /* device name */
};
OpenPOWER on IntegriCloud