From 90edda31ba90c3e4fd07d5dc3671c8210384d994 Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Fri, 26 Apr 2013 16:31:03 +0000 Subject: [PATCH] Added automatic detection of non-rotating media which disables the use of BIO queue sorting, hence optimising performance for devices such as SSD's Reviewed by: scottl Approved by: pjd (mentor) MFC after: 2 weeks --- sys/cam/ata/ata_da.c | 6 ++- sys/cam/scsi/scsi_all.h | 24 +++++++++++ sys/cam/scsi/scsi_da.c | 89 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 111 insertions(+), 8 deletions(-) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index b39a04b5f365..0039fd807ad3 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1155,7 +1155,11 @@ adaregister(struct cam_periph *periph, void *arg) snprintf(announce_buf, sizeof(announce_buf), "kern.cam.ada.%d.write_cache", periph->unit_number); TUNABLE_INT_FETCH(announce_buf, &softc->write_cache); - softc->sort_io_queue = -1; + /* Disable queue sorting for non-rotatational media by default */ + if (cgd->ident_data.media_rotation_rate == 1) + softc->sort_io_queue = 0; + else + softc->sort_io_queue = -1; adagetparams(periph, cgd); softc->disk = disk_alloc(); softc->disk->d_devstat = devstat_new_entry(periph->periph_name, diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h index 1071a5600274..295373100517 100644 --- a/sys/cam/scsi/scsi_all.h +++ b/sys/cam/scsi/scsi_all.h @@ -1429,6 +1429,30 @@ struct scsi_diag_page { uint8_t params[0]; }; +/* + * Block Device Characteristics VPD Page based on + * T10/1799-D Revision 31 + */ +struct scsi_vpd_block_characteristics +{ + u_int8_t device; + u_int8_t page_code; +#define SVPD_BDC 0xB1 + u_int8_t page_length[2]; + u_int8_t medium_rotation_rate[2]; +#define SVPD_BDC_RATE_NOT_REPORTED 0x00 +#define SVPD_BDC_RATE_NONE_ROTATING 0x01 + u_int8_t reserved1; + u_int8_t nominal_form_factor; +#define SVPD_BDC_FORM_NOT_REPORTED 0x00 +#define SVPD_BDC_FORM_5_25INCH 0x01 +#define SVPD_BDC_FORM_3_5INCH 0x02 +#define SVPD_BDC_FORM_2_5INCH 0x03 +#define SVPD_BDC_FORM_1_5INCH 0x04 +#define SVPD_BDC_FORM_LESSTHAN_1_5INCH 0x05 + u_int8_t reserved2[56]; +}; + /* * Logical Block Provisioning VPD Page based on * T10/1799-D Revision 31 diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 475c26acdf2a..02679ed8aa30 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -72,6 +72,7 @@ typedef enum { DA_STATE_PROBE_RC16, DA_STATE_PROBE_LBP, DA_STATE_PROBE_BLK_LIMITS, + DA_STATE_PROBE_BDC, DA_STATE_PROBE_ATA, DA_STATE_NORMAL } da_state; @@ -104,12 +105,13 @@ typedef enum { DA_CCB_PROBE_RC16 = 0x02, DA_CCB_PROBE_LBP = 0x03, DA_CCB_PROBE_BLK_LIMITS = 0x04, - DA_CCB_PROBE_ATA = 0x05, - DA_CCB_BUFFER_IO = 0x06, - DA_CCB_WAITING = 0x07, - DA_CCB_DUMP = 0x08, - DA_CCB_DELETE = 0x0A, - DA_CCB_TUR = 0x0B, + DA_CCB_PROBE_BDC = 0x05, + DA_CCB_PROBE_ATA = 0x06, + DA_CCB_BUFFER_IO = 0x07, + DA_CCB_WAITING = 0x08, + DA_CCB_DUMP = 0x0A, + DA_CCB_DELETE = 0x0B, + DA_CCB_TUR = 0x0C, DA_CCB_TYPE_MASK = 0x0F, DA_CCB_RETRY_UA = 0x10 } da_ccb_state; @@ -2424,6 +2426,39 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) xpt_action(start_ccb); break; } + case DA_STATE_PROBE_BDC: + { + struct scsi_vpd_block_characteristics *bdc; + + if (!scsi_vpd_supported_page(periph, SVPD_BDC)) { + softc->state = DA_STATE_PROBE_ATA; + goto skipstate; + } + + bdc = (struct scsi_vpd_block_characteristics *) + malloc(sizeof(*bdc), M_SCSIDA, M_NOWAIT|M_ZERO); + + if (bdc == NULL) { + printf("dastart: Couldn't malloc bdc data\n"); + /* da_free_periph??? */ + break; + } + + scsi_inquiry(&start_ccb->csio, + /*retries*/da_retry_count, + /*cbfcnp*/dadone, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*inq_buf*/(u_int8_t *)bdc, + /*inq_len*/sizeof(*bdc), + /*evpd*/TRUE, + /*page_code*/SVPD_BDC, + /*sense_len*/SSD_MIN_SIZE, + /*timeout*/da_default_timeout * 1000); + start_ccb->ccb_h.ccb_bp = NULL; + start_ccb->ccb_h.ccb_state = DA_CCB_PROBE_BDC; + xpt_action(start_ccb); + break; + } case DA_STATE_PROBE_ATA: { struct ata_params *ata_params; @@ -2904,7 +2939,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } xpt_release_ccb(done_ccb); - softc->state = DA_STATE_PROBE_ATA; + softc->state = DA_STATE_PROBE_BDC; xpt_schedule(periph, priority); return; } @@ -3027,6 +3062,40 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) xpt_schedule(periph, priority); return; } + case DA_CCB_PROBE_BDC: + { + struct scsi_vpd_block_characteristics *bdc; + + bdc = (struct scsi_vpd_block_characteristics *)csio->data_ptr; + + if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + if (scsi_2btoul(bdc->medium_rotation_rate) == + SVPD_BDC_RATE_NONE_ROTATING) + softc->sort_io_queue = 0; + } else { + int error; + error = daerror(done_ccb, CAM_RETRY_SELTO, + SF_RETRY_UA|SF_NO_PRINT); + if (error == ERESTART) + return; + else if (error != 0) { + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + /* Don't wedge this device's queue */ + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + } + } + } + + free(bdc, M_SCSIDA); + softc->state = DA_STATE_PROBE_ATA; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } case DA_CCB_PROBE_ATA: { int i; @@ -3047,6 +3116,12 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) ata_params->max_dsm_blocks * ATA_DSM_BLK_RANGES); } + /* + * Disable queue sorting for non-rotatational media + * by default + */ + if (ata_params->media_rotation_rate == 1) + softc->sort_io_queue = 0; } else { int error; error = daerror(done_ccb, CAM_RETRY_SELTO,