#include <smartpqi.h>
#define SIS_CMD_GET_ADAPTER_PROPERTIES 0x19
#define SIS_CMD_INIT_BASE_STRUCT_ADDRESS 0x1b
#define SIS_CMD_GET_PQI_CAPABILITIES 0x3000
#define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000
#define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2
#define SIS_PQI_MODE_SUPPORTED 0x4
#define SIS_REQUIRED_EXTENDED_PROPERTIES \
(SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)
typedef struct sis_sync_cmd_params {
uint32_t mailbox[6];
} __packed sis_sync_cmd_params_t;
#define SIS_BASE_STRUCT_REVISION 9
typedef struct sis_base_struct {
uint32_t sb_revision;
uint32_t sb_flags;
uint32_t sb_error_buffer_paddr_low;
uint32_t sb_error_buffer_paddr_high;
uint32_t sb_error_elements_len;
uint32_t sb_error_elements_num;
} __packed sis_base_struct_t;
static boolean_t sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd,
sis_sync_cmd_params_t *params);
uint32_t
sis_read_scratch(pqi_state_t *s)
{
return (G32(s, sis_driver_scratch));
}
void
sis_write_scratch(pqi_state_t *s, int mode)
{
S32(s, sis_driver_scratch, mode);
}
boolean_t
sis_reenable_mode(pqi_state_t *s)
{
int loop_count;
uint32_t doorbell;
S32(s, sis_host_to_ctrl_doorbell, SIS_REENABLE_SIS_MODE);
for (loop_count = 0; loop_count < 1000; loop_count++) {
doorbell = G32(s, sis_ctrl_to_host_doorbell);
if ((doorbell & SIS_REENABLE_SIS_MODE) == 0) {
return (B_TRUE);
}
drv_usecwait(MICROSEC / MILLISEC);
}
return (B_FALSE);
}
boolean_t
sis_wait_for_ctrl_ready(pqi_state_t *s)
{
int loop_count;
uint32_t status;
for (loop_count = 0; loop_count < 1000; loop_count++) {
status = G32(s, sis_firmware_status);
if (status & SIS_CTRL_KERNEL_PANIC)
return (B_FALSE);
if (status & SIS_CTRL_KERNEL_UP)
return (B_TRUE);
drv_usecwait(MICROSEC / MILLISEC);
}
return (B_FALSE);
}
boolean_t
sis_get_ctrl_props(pqi_state_t *s)
{
sis_sync_cmd_params_t p;
uint32_t property;
uint32_t extended_property;
(void) memset(&p, 0, sizeof (p));
if (sis_send_sync_cmd(s, SIS_CMD_GET_ADAPTER_PROPERTIES, &p) == B_FALSE)
return (B_FALSE);
property = p.mailbox[1];
if (!(property & SIS_EXTENDED_PROPERTIES_SUPPORTED))
return (B_FALSE);
extended_property = p.mailbox[4];
if ((extended_property & SIS_REQUIRED_EXTENDED_PROPERTIES) !=
SIS_REQUIRED_EXTENDED_PROPERTIES)
return (B_FALSE);
return (B_TRUE);
}
boolean_t
sis_get_pqi_capabilities(pqi_state_t *s)
{
sis_sync_cmd_params_t p;
(void) memset(&p, 0, sizeof (p));
if (sis_send_sync_cmd(s, SIS_CMD_GET_PQI_CAPABILITIES, &p) == B_FALSE)
return (B_FALSE);
s->s_max_sg_entries = p.mailbox[1];
s->s_max_xfer_size = p.mailbox[2];
s->s_max_outstanding_requests = p.mailbox[3];
s->s_config_table_offset = p.mailbox[4];
s->s_config_table_len = p.mailbox[5];
return (B_TRUE);
}
boolean_t
sis_init_base_struct_addr(pqi_state_t *s)
{
sis_base_struct_t *base;
pqi_dma_overhead_t *o;
sis_sync_cmd_params_t params;
boolean_t rc;
void *dma_addr;
o = pqi_alloc_single(s, sizeof (*base) + SIS_BASE_STRUCT_ALIGNMENT);
if (o == NULL)
return (B_FALSE);
base = PQIALIGN_TYPED(o->alloc_memory, SIS_BASE_STRUCT_ALIGNMENT,
sis_base_struct_t *);
base->sb_revision = SIS_BASE_STRUCT_REVISION;
base->sb_error_buffer_paddr_low = (uint32_t)s->s_error_dma->dma_addr;
base->sb_error_buffer_paddr_high =
(uint32_t)(s->s_error_dma->dma_addr >> 32);
base->sb_error_elements_len = PQI_ERROR_BUFFER_ELEMENT_LENGTH;
base->sb_error_elements_num = s->s_max_outstanding_requests;
dma_addr = PQIALIGN_TYPED(o->dma_addr, SIS_BASE_STRUCT_ALIGNMENT,
void *);
(void) memset(¶ms, 0, sizeof (params));
params.mailbox[1] = (uint32_t)(uintptr_t)dma_addr;
params.mailbox[2] = (uint32_t)((uint64_t)((uintptr_t)dma_addr) >> 32);
params.mailbox[3] = sizeof (*base);
(void) ddi_dma_sync(o->handle, 0, 0, DDI_DMA_SYNC_FORDEV);
rc = sis_send_sync_cmd(s, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, ¶ms);
pqi_free_single(s, o);
return (rc);
}
static boolean_t
sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd,
sis_sync_cmd_params_t *params)
{
uint32_t i;
uint32_t doorbell;
uint32_t cmd_status;
S32(s, sis_mailbox[0], cmd);
for (i = 1; i <= 4; i++)
S32(s, sis_mailbox[i], params->mailbox[i]);
S32(s, sis_ctrl_to_host_doorbell_clear,
SIS_CLEAR_CTRL_TO_HOST_DOORBELL);
S32(s, sis_interrupt_mask, ~0);
(void) G32(s, sis_interrupt_mask);
S32(s, sis_host_to_ctrl_doorbell, SIS_CMD_READY);
for (i = 0; i < 10000; i++) {
drv_usecwait(MICROSEC / MILLISEC);
doorbell = G32(s, sis_ctrl_to_host_doorbell);
if (doorbell & SIS_CMD_COMPLETE)
break;
}
if (i == 10000)
return (B_FALSE);
cmd_status = G32(s, sis_mailbox[0]);
if (cmd_status != SIS_CMD_STATUS_SUCCESS)
return (B_FALSE);
params->mailbox[0] = cmd_status;
for (i = 1; i < ARRAY_SIZE(params->mailbox); i++)
params->mailbox[i] = G32(s, sis_mailbox[i]);
return (B_TRUE);
}