Some groundwork for later Informational Exceptions support.
This includes support for: - Read-Write Error Recovery mode page; - Informational Exceptions Control mode page; - Logical Block Provisioning mode page; - LOG SENSE command. No real Informational Exceptions features yet. This is only a placeholder. Sponsored by: iXsystems, Inc.
This commit is contained in:
parent
871e8858c4
commit
eeba2f63ea
@ -178,6 +178,34 @@ static struct copan_debugconf_subpage debugconf_page_changeable = {
|
||||
{0xff,0xff}, /* ctl_time_io_secs */
|
||||
};
|
||||
|
||||
static struct scsi_da_rw_recovery_page rw_er_page_default = {
|
||||
/*page_code*/SMS_RW_ERROR_RECOVERY_PAGE,
|
||||
/*page_length*/sizeof(struct scsi_da_rw_recovery_page) - 2,
|
||||
/*byte3*/SMS_RWER_AWRE|SMS_RWER_ARRE,
|
||||
/*read_retry_count*/0,
|
||||
/*correction_span*/0,
|
||||
/*head_offset_count*/0,
|
||||
/*data_strobe_offset_cnt*/0,
|
||||
/*byte8*/0,
|
||||
/*write_retry_count*/0,
|
||||
/*reserved2*/0,
|
||||
/*recovery_time_limit*/{0, 0},
|
||||
};
|
||||
|
||||
static struct scsi_da_rw_recovery_page rw_er_page_changeable = {
|
||||
/*page_code*/SMS_RW_ERROR_RECOVERY_PAGE,
|
||||
/*page_length*/sizeof(struct scsi_da_rw_recovery_page) - 2,
|
||||
/*byte3*/0,
|
||||
/*read_retry_count*/0,
|
||||
/*correction_span*/0,
|
||||
/*head_offset_count*/0,
|
||||
/*data_strobe_offset_cnt*/0,
|
||||
/*byte8*/0,
|
||||
/*write_retry_count*/0,
|
||||
/*reserved2*/0,
|
||||
/*recovery_time_limit*/{0, 0},
|
||||
};
|
||||
|
||||
static struct scsi_format_page format_page_default = {
|
||||
/*page_code*/SMS_FORMAT_DEVICE_PAGE,
|
||||
/*page_length*/sizeof(struct scsi_format_page) - 2,
|
||||
@ -300,6 +328,41 @@ static struct scsi_control_page control_page_changeable = {
|
||||
/*extended_selftest_completion_time*/{0, 0}
|
||||
};
|
||||
|
||||
static struct scsi_info_exceptions_page ie_page_default = {
|
||||
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE,
|
||||
/*page_length*/sizeof(struct scsi_info_exceptions_page) - 2,
|
||||
/*info_flags*/SIEP_FLAGS_DEXCPT,
|
||||
/*mrie*/0,
|
||||
/*interval_timer*/{0, 0, 0, 0},
|
||||
/*report_count*/{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct scsi_info_exceptions_page ie_page_changeable = {
|
||||
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE,
|
||||
/*page_length*/sizeof(struct scsi_info_exceptions_page) - 2,
|
||||
/*info_flags*/0,
|
||||
/*mrie*/0,
|
||||
/*interval_timer*/{0, 0, 0, 0},
|
||||
/*report_count*/{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct scsi_logical_block_provisioning_page lbp_page_default = {
|
||||
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
|
||||
/*subpage_code*/0x02,
|
||||
/*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
|
||||
/*flags*/0,
|
||||
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
/*descr*/{}
|
||||
};
|
||||
|
||||
static struct scsi_logical_block_provisioning_page lbp_page_changeable = {
|
||||
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
|
||||
/*subpage_code*/0x02,
|
||||
/*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
|
||||
/*flags*/0,
|
||||
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
/*descr*/{}
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX KDM move these into the softc.
|
||||
@ -4153,14 +4216,11 @@ ctl_init_page_index(struct ctl_lun *lun)
|
||||
{
|
||||
int i;
|
||||
struct ctl_page_index *page_index;
|
||||
struct ctl_softc *softc;
|
||||
const char *value;
|
||||
|
||||
memcpy(&lun->mode_pages.index, page_index_template,
|
||||
sizeof(page_index_template));
|
||||
|
||||
softc = lun->ctl_softc;
|
||||
|
||||
for (i = 0; i < CTL_NUM_MODE_PAGES; i++) {
|
||||
|
||||
page_index = &lun->mode_pages.index[i];
|
||||
@ -4175,6 +4235,25 @@ ctl_init_page_index(struct ctl_lun *lun)
|
||||
continue;
|
||||
|
||||
switch (page_index->page_code & SMPH_PC_MASK) {
|
||||
case SMS_RW_ERROR_RECOVERY_PAGE: {
|
||||
if (page_index->subpage != SMS_SUBPAGE_PAGE_0)
|
||||
panic("subpage is incorrect!");
|
||||
memcpy(&lun->mode_pages.rw_er_page[CTL_PAGE_CURRENT],
|
||||
&rw_er_page_default,
|
||||
sizeof(rw_er_page_default));
|
||||
memcpy(&lun->mode_pages.rw_er_page[CTL_PAGE_CHANGEABLE],
|
||||
&rw_er_page_changeable,
|
||||
sizeof(rw_er_page_changeable));
|
||||
memcpy(&lun->mode_pages.rw_er_page[CTL_PAGE_DEFAULT],
|
||||
&rw_er_page_default,
|
||||
sizeof(rw_er_page_default));
|
||||
memcpy(&lun->mode_pages.rw_er_page[CTL_PAGE_SAVED],
|
||||
&rw_er_page_default,
|
||||
sizeof(rw_er_page_default));
|
||||
page_index->page_data =
|
||||
(uint8_t *)lun->mode_pages.rw_er_page;
|
||||
break;
|
||||
}
|
||||
case SMS_FORMAT_DEVICE_PAGE: {
|
||||
struct scsi_format_page *format_page;
|
||||
|
||||
@ -4364,6 +4443,42 @@ ctl_init_page_index(struct ctl_lun *lun)
|
||||
break;
|
||||
|
||||
}
|
||||
case SMS_INFO_EXCEPTIONS_PAGE: {
|
||||
switch (page_index->subpage) {
|
||||
case SMS_SUBPAGE_PAGE_0:
|
||||
memcpy(&lun->mode_pages.ie_page[CTL_PAGE_CURRENT],
|
||||
&ie_page_default,
|
||||
sizeof(ie_page_default));
|
||||
memcpy(&lun->mode_pages.ie_page[
|
||||
CTL_PAGE_CHANGEABLE], &ie_page_changeable,
|
||||
sizeof(ie_page_changeable));
|
||||
memcpy(&lun->mode_pages.ie_page[CTL_PAGE_DEFAULT],
|
||||
&ie_page_default,
|
||||
sizeof(ie_page_default));
|
||||
memcpy(&lun->mode_pages.ie_page[CTL_PAGE_SAVED],
|
||||
&ie_page_default,
|
||||
sizeof(ie_page_default));
|
||||
page_index->page_data =
|
||||
(uint8_t *)lun->mode_pages.ie_page;
|
||||
break;
|
||||
case 0x02:
|
||||
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_CURRENT],
|
||||
&lbp_page_default,
|
||||
sizeof(lbp_page_default));
|
||||
memcpy(&lun->mode_pages.lbp_page[
|
||||
CTL_PAGE_CHANGEABLE], &lbp_page_changeable,
|
||||
sizeof(lbp_page_changeable));
|
||||
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_DEFAULT],
|
||||
&lbp_page_default,
|
||||
sizeof(lbp_page_default));
|
||||
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_SAVED],
|
||||
&lbp_page_default,
|
||||
sizeof(lbp_page_default));
|
||||
page_index->page_data =
|
||||
(uint8_t *)lun->mode_pages.lbp_page;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMS_VENDOR_SPECIFIC_PAGE:{
|
||||
switch (page_index->subpage) {
|
||||
case PWR_SUBPAGE_CODE: {
|
||||
@ -4487,6 +4602,45 @@ ctl_init_page_index(struct ctl_lun *lun)
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
static int
|
||||
ctl_init_log_page_index(struct ctl_lun *lun)
|
||||
{
|
||||
struct ctl_page_index *page_index;
|
||||
int i, j, prev;
|
||||
|
||||
memcpy(&lun->log_pages.index, log_page_index_template,
|
||||
sizeof(log_page_index_template));
|
||||
|
||||
prev = -1;
|
||||
for (i = 0, j = 0; i < CTL_NUM_LOG_PAGES; i++) {
|
||||
|
||||
page_index = &lun->log_pages.index[i];
|
||||
/*
|
||||
* If this is a disk-only mode page, there's no point in
|
||||
* setting it up. For some pages, we have to have some
|
||||
* basic information about the disk in order to calculate the
|
||||
* mode page data.
|
||||
*/
|
||||
if ((lun->be_lun->lun_type != T_DIRECT)
|
||||
&& (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY))
|
||||
continue;
|
||||
|
||||
if (page_index->page_code != prev) {
|
||||
lun->log_pages.pages_page[j] = page_index->page_code;
|
||||
prev = page_index->page_code;
|
||||
j++;
|
||||
}
|
||||
lun->log_pages.subpages_page[i*2] = page_index->page_code;
|
||||
lun->log_pages.subpages_page[i*2+1] = page_index->subpage;
|
||||
}
|
||||
lun->log_pages.index[0].page_data = &lun->log_pages.pages_page[0];
|
||||
lun->log_pages.index[0].page_len = j;
|
||||
lun->log_pages.index[1].page_data = &lun->log_pages.subpages_page[0];
|
||||
lun->log_pages.index[1].page_len = i * 2;
|
||||
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
/*
|
||||
* LUN allocation.
|
||||
*
|
||||
@ -4682,9 +4836,10 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun,
|
||||
ctl_tpc_lun_init(lun);
|
||||
|
||||
/*
|
||||
* Initialize the mode page index.
|
||||
* Initialize the mode and log page index.
|
||||
*/
|
||||
ctl_init_page_index(lun);
|
||||
ctl_init_log_page_index(lun);
|
||||
|
||||
/*
|
||||
* Set the poweron UA for all initiators on this LUN only.
|
||||
@ -7265,6 +7420,91 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
int
|
||||
ctl_log_sense(struct ctl_scsiio *ctsio)
|
||||
{
|
||||
struct ctl_lun *lun;
|
||||
int i, pc, page_code, subpage;
|
||||
int alloc_len, total_len;
|
||||
struct ctl_page_index *page_index;
|
||||
struct scsi_log_sense *cdb;
|
||||
struct scsi_log_header *header;
|
||||
|
||||
CTL_DEBUG_PRINT(("ctl_log_sense\n"));
|
||||
|
||||
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
|
||||
cdb = (struct scsi_log_sense *)ctsio->cdb;
|
||||
pc = (cdb->page & SLS_PAGE_CTRL_MASK) >> 6;
|
||||
page_code = cdb->page & SLS_PAGE_CODE;
|
||||
subpage = cdb->subpage;
|
||||
alloc_len = scsi_2btoul(cdb->length);
|
||||
|
||||
page_index = NULL;
|
||||
for (i = 0; i < CTL_NUM_LOG_PAGES; i++) {
|
||||
page_index = &lun->log_pages.index[i];
|
||||
|
||||
/* Look for the right page code */
|
||||
if ((page_index->page_code & SL_PAGE_CODE) != page_code)
|
||||
continue;
|
||||
|
||||
/* Look for the right subpage or the subpage wildcard*/
|
||||
if (page_index->subpage != subpage)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
if (i >= CTL_NUM_LOG_PAGES) {
|
||||
ctl_set_invalid_field(ctsio,
|
||||
/*sks_valid*/ 1,
|
||||
/*command*/ 1,
|
||||
/*field*/ 2,
|
||||
/*bit_valid*/ 0,
|
||||
/*bit*/ 0);
|
||||
ctl_done((union ctl_io *)ctsio);
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
total_len = sizeof(struct scsi_log_header) + page_index->page_len;
|
||||
|
||||
ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
|
||||
ctsio->kern_sg_entries = 0;
|
||||
ctsio->kern_data_resid = 0;
|
||||
ctsio->kern_rel_offset = 0;
|
||||
if (total_len < alloc_len) {
|
||||
ctsio->residual = alloc_len - total_len;
|
||||
ctsio->kern_data_len = total_len;
|
||||
ctsio->kern_total_len = total_len;
|
||||
} else {
|
||||
ctsio->residual = 0;
|
||||
ctsio->kern_data_len = alloc_len;
|
||||
ctsio->kern_total_len = alloc_len;
|
||||
}
|
||||
|
||||
header = (struct scsi_log_header *)ctsio->kern_data_ptr;
|
||||
header->page = page_index->page_code;
|
||||
if (page_index->subpage) {
|
||||
header->page |= SL_SPF;
|
||||
header->subpage = page_index->subpage;
|
||||
}
|
||||
scsi_ulto2b(page_index->page_len, header->datalen);
|
||||
|
||||
/*
|
||||
* Call the handler, if it exists, to update the
|
||||
* page to the latest values.
|
||||
*/
|
||||
if (page_index->sense_handler != NULL)
|
||||
page_index->sense_handler(ctsio, page_index, pc);
|
||||
|
||||
memcpy(header + 1, page_index->page_data, page_index->page_len);
|
||||
|
||||
ctsio->scsi_status = SCSI_STATUS_OK;
|
||||
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
|
||||
ctsio->be_move_done = ctl_config_move_done;
|
||||
ctl_datamove((union ctl_io *)ctsio);
|
||||
|
||||
return (CTL_RETVAL_COMPLETE);
|
||||
}
|
||||
|
||||
int
|
||||
ctl_read_capacity(struct ctl_scsiio *ctsio)
|
||||
{
|
||||
|
@ -850,7 +850,10 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
|
||||
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
|
||||
|
||||
/* 4D LOG SENSE */
|
||||
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
|
||||
{ctl_log_sense, CTL_SERIDX_LOG_SNS, CTL_CMD_FLAG_OK_ON_SLUN |
|
||||
CTL_FLAG_DATA_IN |
|
||||
CTL_CMD_FLAG_ALLOW_ON_PR_RESV,
|
||||
CTL_LUN_PAT_NONE, 10, {0, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0x07} },
|
||||
|
||||
/* 4E STOP PLAY/SCAN */
|
||||
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
|
||||
|
@ -302,6 +302,8 @@ struct ctl_page_index {
|
||||
#define CTL_PAGE_SAVED 0x03
|
||||
|
||||
static const struct ctl_page_index page_index_template[] = {
|
||||
{SMS_RW_ERROR_RECOVERY_PAGE, 0, sizeof(struct scsi_da_rw_recovery_page), NULL,
|
||||
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
|
||||
{SMS_FORMAT_DEVICE_PAGE, 0, sizeof(struct scsi_format_page), NULL,
|
||||
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
|
||||
{SMS_RIGID_DISK_PAGE, 0, sizeof(struct scsi_rigid_disk_page), NULL,
|
||||
@ -310,6 +312,11 @@ static const struct ctl_page_index page_index_template[] = {
|
||||
CTL_PAGE_FLAG_DISK_ONLY, NULL, ctl_caching_sp_handler},
|
||||
{SMS_CONTROL_MODE_PAGE, 0, sizeof(struct scsi_control_page), NULL,
|
||||
CTL_PAGE_FLAG_NONE, NULL, ctl_control_page_handler},
|
||||
{SMS_INFO_EXCEPTIONS_PAGE, 0, sizeof(struct scsi_info_exceptions_page), NULL,
|
||||
CTL_PAGE_FLAG_NONE, NULL, NULL},
|
||||
{SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF, 0x02,
|
||||
sizeof(struct scsi_logical_block_provisioning_page), NULL,
|
||||
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
|
||||
{SMS_VENDOR_SPECIFIC_PAGE | SMPH_SPF, PWR_SUBPAGE_CODE,
|
||||
sizeof(struct copan_power_subpage), NULL, CTL_PAGE_FLAG_NONE,
|
||||
ctl_power_sp_sense_handler, ctl_power_sp_handler},
|
||||
@ -325,16 +332,35 @@ static const struct ctl_page_index page_index_template[] = {
|
||||
sizeof(page_index_template[0])
|
||||
|
||||
struct ctl_mode_pages {
|
||||
struct scsi_da_rw_recovery_page rw_er_page[4];
|
||||
struct scsi_format_page format_page[4];
|
||||
struct scsi_rigid_disk_page rigid_disk_page[4];
|
||||
struct scsi_caching_page caching_page[4];
|
||||
struct scsi_control_page control_page[4];
|
||||
struct scsi_info_exceptions_page ie_page[4];
|
||||
struct scsi_logical_block_provisioning_page lbp_page[4];
|
||||
struct copan_power_subpage power_subpage[4];
|
||||
struct copan_aps_subpage aps_subpage[4];
|
||||
struct copan_debugconf_subpage debugconf_subpage[4];
|
||||
struct ctl_page_index index[CTL_NUM_MODE_PAGES];
|
||||
};
|
||||
|
||||
static const struct ctl_page_index log_page_index_template[] = {
|
||||
{SLS_SUPPORTED_PAGES_PAGE, 0, 0, NULL,
|
||||
CTL_PAGE_FLAG_NONE, NULL, NULL},
|
||||
{SLS_SUPPORTED_PAGES_PAGE, SLS_SUPPORTED_SUBPAGES_SUBPAGE, 0, NULL,
|
||||
CTL_PAGE_FLAG_NONE, NULL, NULL},
|
||||
};
|
||||
|
||||
#define CTL_NUM_LOG_PAGES sizeof(log_page_index_template)/ \
|
||||
sizeof(log_page_index_template[0])
|
||||
|
||||
struct ctl_log_pages {
|
||||
uint8_t pages_page[CTL_NUM_LOG_PAGES];
|
||||
uint8_t subpages_page[CTL_NUM_LOG_PAGES * 2];
|
||||
struct ctl_page_index index[CTL_NUM_LOG_PAGES];
|
||||
};
|
||||
|
||||
struct ctl_lun_delay_info {
|
||||
ctl_delay_type datamove_type;
|
||||
uint32_t datamove_delay;
|
||||
@ -391,6 +417,7 @@ struct ctl_lun {
|
||||
#endif
|
||||
ctl_ua_type pending_ua[CTL_MAX_INITIATORS];
|
||||
struct ctl_mode_pages mode_pages;
|
||||
struct ctl_log_pages log_pages;
|
||||
struct ctl_lun_io_stats stats;
|
||||
uint32_t res_idx;
|
||||
unsigned int PRGeneration;
|
||||
@ -484,6 +511,7 @@ int ctl_write_same(struct ctl_scsiio *ctsio);
|
||||
int ctl_unmap(struct ctl_scsiio *ctsio);
|
||||
int ctl_mode_select(struct ctl_scsiio *ctsio);
|
||||
int ctl_mode_sense(struct ctl_scsiio *ctsio);
|
||||
int ctl_log_sense(struct ctl_scsiio *ctsio);
|
||||
int ctl_read_capacity(struct ctl_scsiio *ctsio);
|
||||
int ctl_read_capacity_16(struct ctl_scsiio *ctsio);
|
||||
int ctl_read_defect(struct ctl_scsiio *ctsio);
|
||||
|
@ -551,7 +551,7 @@ struct scsi_log_sense
|
||||
#define SLS_PPC 0x02
|
||||
u_int8_t page;
|
||||
#define SLS_PAGE_CODE 0x3F
|
||||
#define SLS_ALL_PAGES_PAGE 0x00
|
||||
#define SLS_SUPPORTED_PAGES_PAGE 0x00
|
||||
#define SLS_OVERRUN_PAGE 0x01
|
||||
#define SLS_ERROR_WRITE_PAGE 0x02
|
||||
#define SLS_ERROR_READ_PAGE 0x03
|
||||
@ -566,7 +566,9 @@ struct scsi_log_sense
|
||||
#define SLS_PAGE_CTRL_CUMULATIVE 0x40
|
||||
#define SLS_PAGE_CTRL_THRESH_DEFAULT 0x80
|
||||
#define SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t subpage;
|
||||
#define SLS_SUPPORTED_SUBPAGES_SUBPAGE 0xff
|
||||
u_int8_t reserved;
|
||||
u_int8_t paramptr[2];
|
||||
u_int8_t length[2];
|
||||
u_int8_t control;
|
||||
@ -592,7 +594,10 @@ struct scsi_log_select
|
||||
struct scsi_log_header
|
||||
{
|
||||
u_int8_t page;
|
||||
u_int8_t reserved;
|
||||
#define SL_PAGE_CODE 0x3F
|
||||
#define SL_SPF 0x40
|
||||
#define SL_DS 0x80
|
||||
u_int8_t subpage;
|
||||
u_int8_t datalen[2];
|
||||
};
|
||||
|
||||
@ -767,6 +772,23 @@ struct scsi_info_exceptions_page {
|
||||
u_int8_t report_count[4];
|
||||
};
|
||||
|
||||
struct scsi_logical_block_provisioning_page_descr {
|
||||
uint8_t flags;
|
||||
uint8_t resource;
|
||||
uint8_t reserved[2];
|
||||
uint8_t count[4];
|
||||
};
|
||||
|
||||
struct scsi_logical_block_provisioning_page {
|
||||
uint8_t page_code;
|
||||
uint8_t subpage_code;
|
||||
uint8_t page_length[2];
|
||||
uint8_t flags;
|
||||
#define SLBPP_SITUA 0x01
|
||||
uint8_t reserved[11];
|
||||
struct scsi_logical_block_provisioning_page_descr descr[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* SCSI protocol identifier values, current as of SPC4r36l.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user