From 440baa08c3de75b936f74211758f1bf3ffe79890 Mon Sep 17 00:00:00 2001 From: Paul Saab Date: Wed, 5 Feb 2003 08:43:46 +0000 Subject: [PATCH] Properly get the drive geometry from the controller. This should fix booting off of volumes > 255GB. --- sys/dev/ciss/ciss.c | 102 +++++++++++++++++++++++++++++++++++++---- sys/dev/ciss/cissreg.h | 15 ++++++ sys/dev/ciss/cissvar.h | 1 + 3 files changed, 108 insertions(+), 10 deletions(-) diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c index 342bed897ec3..f2122b7fe1b2 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. */ @@ -1070,6 +1131,12 @@ ciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld) if ((error = ciss_get_ldrive_status(sc, ld)) != 0) goto out; + /* + * Get the logical drive geometry. + */ + if ((error = ciss_inquiry_logical(sc, ld)) != 0) + goto out; + /* * Print the drive's basic characteristics. */ @@ -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 2e5e71ec5328..c7844e90a1bd 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 5baa136c395a..4c102e04cc85 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 */ };