Use READ CAPACITY(16) to get information about device physical sectors.
As soon as not all devices support READ CAPACITY(16), automatically fall back to READ CAPACITY(10) if CAM_REQ_INVALID or SSD_KEY_ILLEGAL_REQUEST status returned. It also provides first bits of information about Logical Block Provisioning (aka UNMAP/TRIM) support by the device.
This commit is contained in:
parent
d0c7b0751a
commit
f67daabb25
@ -1349,6 +1349,17 @@ struct scsi_read_capacity_data_long
|
||||
{
|
||||
uint8_t addr[8];
|
||||
uint8_t length[4];
|
||||
#define SRC16_PROT_EN 0x01
|
||||
#define SRC16_P_TYPE 0x0e
|
||||
uint8_t prot;
|
||||
#define SRC16_LBPPBE 0x0f
|
||||
#define SRC16_PI_EXPONENT 0xf0
|
||||
#define SRC16_PI_EXPONENT_SHIFT 4
|
||||
uint8_t prot_lbppbe;
|
||||
#define SRC16_LALBA 0x3fff
|
||||
#define SRC16_LBPRZ 0x4000
|
||||
#define SRC16_LBPME 0x8000
|
||||
uint8_t lalba_lbp[2];
|
||||
};
|
||||
|
||||
struct scsi_report_luns
|
||||
|
@ -82,7 +82,9 @@ typedef enum {
|
||||
DA_FLAG_WENT_IDLE = 0x040,
|
||||
DA_FLAG_RETRY_UA = 0x080,
|
||||
DA_FLAG_OPEN = 0x100,
|
||||
DA_FLAG_SCTX_INIT = 0x200
|
||||
DA_FLAG_SCTX_INIT = 0x200,
|
||||
DA_FLAG_CAN_RC16 = 0x400,
|
||||
DA_FLAG_CAN_LBPME = 0x800
|
||||
} da_flags;
|
||||
|
||||
typedef enum {
|
||||
@ -1533,6 +1535,14 @@ daregister(struct cam_periph *periph, void *arg)
|
||||
else if (softc->minimum_cmd_size > 12)
|
||||
softc->minimum_cmd_size = 16;
|
||||
|
||||
/* Predict whether device may support READ CAPACITY(16). */
|
||||
if (SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC3 ||
|
||||
(SID_ANSI_REV(&cgd->inq_data) >= SCSI_REV_SPC &&
|
||||
(cgd->inq_data.spc3_flags & SPC3_SID_PROTECT))) {
|
||||
softc->flags |= DA_FLAG_CAN_RC16;
|
||||
softc->state = DA_STATE_PROBE2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register this media as a disk.
|
||||
*/
|
||||
@ -1922,10 +1932,14 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
struct disk_params *dp;
|
||||
uint32_t block_size;
|
||||
uint64_t maxsector;
|
||||
u_int lbppbe; /* LB per physical block exponent. */
|
||||
u_int lalba; /* Lowest aligned LBA. */
|
||||
|
||||
if (softc->state == DA_STATE_PROBE) {
|
||||
block_size = scsi_4btoul(rdcap->length);
|
||||
maxsector = scsi_4btoul(rdcap->addr);
|
||||
lbppbe = 0;
|
||||
lalba = 0;
|
||||
|
||||
/*
|
||||
* According to SBC-2, if the standard 10
|
||||
@ -1945,6 +1959,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
} else {
|
||||
block_size = scsi_4btoul(rcaplong->length);
|
||||
maxsector = scsi_8btou64(rcaplong->addr);
|
||||
lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE;
|
||||
lalba = scsi_2btoul(rcaplong->lalba_lbp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1962,7 +1978,12 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
announce_buf[0] = '\0';
|
||||
cam_periph_invalidate(periph);
|
||||
} else {
|
||||
dasetgeom(periph, block_size, maxsector, 0, 0);
|
||||
dasetgeom(periph, block_size, maxsector,
|
||||
lbppbe, lalba & SRC16_LALBA);
|
||||
if (lalba & SRC16_LBPME)
|
||||
softc->flags |= DA_FLAG_CAN_LBPME;
|
||||
else
|
||||
softc->flags &= ~DA_FLAG_CAN_LBPME;
|
||||
dp = &softc->params;
|
||||
snprintf(announce_buf, sizeof(announce_buf),
|
||||
"%juMB (%ju %u byte sectors: %dH %dS/T "
|
||||
@ -2028,6 +2049,24 @@ dadone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
&error_code, &sense_key, &asc,
|
||||
&ascq, /*show_errors*/ 1);
|
||||
}
|
||||
/*
|
||||
* If we tried READ CAPACITY(16) and failed,
|
||||
* fallback to READ CAPACITY(10).
|
||||
*/
|
||||
if ((softc->state == DA_STATE_PROBE2) &&
|
||||
(softc->flags & DA_FLAG_CAN_RC16) &&
|
||||
(((csio->ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_REQ_INVALID) ||
|
||||
((have_sense) &&
|
||||
(error_code == SSD_CURRENT_ERROR) &&
|
||||
(sense_key == SSD_KEY_ILLEGAL_REQUEST)))) {
|
||||
softc->flags &= ~DA_FLAG_CAN_RC16;
|
||||
softc->state = DA_STATE_PROBE;
|
||||
free(rdcap, M_SCSIDA);
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
} else
|
||||
/*
|
||||
* Attach to anything that claims to be a
|
||||
* direct access or optical disk device,
|
||||
@ -2198,13 +2237,18 @@ dagetcapacity(struct cam_periph *periph)
|
||||
struct scsi_read_capacity_data_long *rcaplong;
|
||||
uint32_t block_len;
|
||||
uint64_t maxsector;
|
||||
int error;
|
||||
int error, rc16failed;
|
||||
u_int32_t sense_flags;
|
||||
u_int lbppbe; /* Logical blocks per physical block exponent. */
|
||||
u_int lalba; /* Lowest aligned LBA. */
|
||||
|
||||
softc = (struct da_softc *)periph->softc;
|
||||
block_len = 0;
|
||||
maxsector = 0;
|
||||
lbppbe = 0;
|
||||
lalba = 0;
|
||||
error = 0;
|
||||
rc16failed = 0;
|
||||
sense_flags = SF_RETRY_UA;
|
||||
if (softc->flags & DA_FLAG_PACK_REMOVABLE)
|
||||
sense_flags |= SF_NO_PRINT;
|
||||
@ -2212,11 +2256,63 @@ dagetcapacity(struct cam_periph *periph)
|
||||
/* Do a read capacity */
|
||||
rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong),
|
||||
M_SCSIDA,
|
||||
M_NOWAIT);
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (rcap == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
rcaplong = (struct scsi_read_capacity_data_long *)rcap;
|
||||
|
||||
ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
|
||||
|
||||
/* Try READ CAPACITY(16) first if we think it should work. */
|
||||
if (softc->flags & DA_FLAG_CAN_RC16) {
|
||||
scsi_read_capacity_16(&ccb->csio,
|
||||
/*retries*/ 4,
|
||||
/*cbfcnp*/ dadone,
|
||||
/*tag_action*/ MSG_SIMPLE_Q_TAG,
|
||||
/*lba*/ 0,
|
||||
/*reladr*/ 0,
|
||||
/*pmi*/ 0,
|
||||
rcaplong,
|
||||
/*sense_len*/ SSD_FULL_SIZE,
|
||||
/*timeout*/ 60000);
|
||||
ccb->ccb_h.ccb_bp = NULL;
|
||||
|
||||
error = cam_periph_runccb(ccb, daerror,
|
||||
/*cam_flags*/CAM_RETRY_SELTO,
|
||||
sense_flags,
|
||||
softc->disk->d_devstat);
|
||||
|
||||
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
|
||||
if (error == 0)
|
||||
goto rc16ok;
|
||||
|
||||
/* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */
|
||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_REQ_INVALID) {
|
||||
softc->flags &= ~DA_FLAG_CAN_RC16;
|
||||
} else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR) &&
|
||||
(ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) &&
|
||||
(ccb->ccb_h.status & CAM_AUTOSNS_VALID) &&
|
||||
((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0) &&
|
||||
((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
|
||||
int sense_key, error_code, asc, ascq;
|
||||
|
||||
scsi_extract_sense(&ccb->csio.sense_data,
|
||||
&error_code, &sense_key, &asc, &ascq);
|
||||
if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
|
||||
softc->flags &= ~DA_FLAG_CAN_RC16;
|
||||
}
|
||||
rc16failed = 1;
|
||||
}
|
||||
|
||||
/* Do READ CAPACITY(10). */
|
||||
scsi_read_capacity(&ccb->csio,
|
||||
/*retries*/4,
|
||||
/*cbfncp*/dadone,
|
||||
@ -2242,13 +2338,12 @@ dagetcapacity(struct cam_periph *periph)
|
||||
block_len = scsi_4btoul(rcap->length);
|
||||
maxsector = scsi_4btoul(rcap->addr);
|
||||
|
||||
if (maxsector != 0xffffffff)
|
||||
if (maxsector != 0xffffffff || rc16failed)
|
||||
goto done;
|
||||
} else
|
||||
goto done;
|
||||
|
||||
rcaplong = (struct scsi_read_capacity_data_long *)rcap;
|
||||
|
||||
/* If READ CAPACITY(10) returned overflow, use READ CAPACITY(16) */
|
||||
scsi_read_capacity_16(&ccb->csio,
|
||||
/*retries*/ 4,
|
||||
/*cbfcnp*/ dadone,
|
||||
@ -2274,8 +2369,11 @@ dagetcapacity(struct cam_periph *periph)
|
||||
/*getcount_only*/0);
|
||||
|
||||
if (error == 0) {
|
||||
rc16ok:
|
||||
block_len = scsi_4btoul(rcaplong->length);
|
||||
maxsector = scsi_8btou64(rcaplong->addr);
|
||||
lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE;
|
||||
lalba = scsi_2btoul(rcaplong->lalba_lbp);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -2286,8 +2384,14 @@ done:
|
||||
"unsupportable block size %ju\n",
|
||||
(uintmax_t) block_len);
|
||||
error = EINVAL;
|
||||
} else
|
||||
dasetgeom(periph, block_len, maxsector, 0, 0);
|
||||
} else {
|
||||
dasetgeom(periph, block_len, maxsector,
|
||||
lbppbe, lalba & SRC16_LALBA);
|
||||
if (lalba & SRC16_LBPME)
|
||||
softc->flags |= DA_FLAG_CAN_LBPME;
|
||||
else
|
||||
softc->flags &= ~DA_FLAG_CAN_LBPME;
|
||||
}
|
||||
}
|
||||
|
||||
xpt_release_ccb(ccb);
|
||||
|
Loading…
x
Reference in New Issue
Block a user