1*8226594fSRick McNeal /*
2*8226594fSRick McNeal  * This file and its contents are supplied under the terms of the
3*8226594fSRick McNeal  * Common Development and Distribution License ("CDDL"), version 1.0.
4*8226594fSRick McNeal  * You may only use this file in accordance with the terms of version
5*8226594fSRick McNeal  * 1.0 of the CDDL.
6*8226594fSRick McNeal  *
7*8226594fSRick McNeal  * A full copy of the text of the CDDL should have accompanied this
8*8226594fSRick McNeal  * source.  A copy of the CDDL is also available via the Internet at
9*8226594fSRick McNeal  * http://www.illumos.org/license/CDDL.
10*8226594fSRick McNeal  */
11*8226594fSRick McNeal 
12*8226594fSRick McNeal /*
13*8226594fSRick McNeal  * Copyright 2018 Nexenta Systems, Inc.
14*8226594fSRick McNeal  */
15*8226594fSRick McNeal 
16*8226594fSRick McNeal /*
17*8226594fSRick McNeal  * A few simple method to access controller when it's in the base mode.
18*8226594fSRick McNeal  */
19*8226594fSRick McNeal #include <smartpqi.h>
20*8226594fSRick McNeal 
21*8226594fSRick McNeal /* ---- legacy SIS interface commands ---- */
22*8226594fSRick McNeal #define	SIS_CMD_GET_ADAPTER_PROPERTIES	0x19
23*8226594fSRick McNeal #define	SIS_CMD_INIT_BASE_STRUCT_ADDRESS	0x1b
24*8226594fSRick McNeal #define	SIS_CMD_GET_PQI_CAPABILITIES		0x3000
25*8226594fSRick McNeal 
26*8226594fSRick McNeal /* ---- used with SIS_CMD_GET_ADAPTER_PROPERTIES command ---- */
27*8226594fSRick McNeal #define	SIS_EXTENDED_PROPERTIES_SUPPORTED	0x800000
28*8226594fSRick McNeal #define	SIS_SMARTARRAY_FEATURES_SUPPORTED	0x2
29*8226594fSRick McNeal #define	SIS_PQI_MODE_SUPPORTED			0x4
30*8226594fSRick McNeal #define	SIS_REQUIRED_EXTENDED_PROPERTIES	\
31*8226594fSRick McNeal 	(SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED)
32*8226594fSRick McNeal 
33*8226594fSRick McNeal /* used for passing command parameters/results when issuing SIS commands */
34*8226594fSRick McNeal typedef struct sis_sync_cmd_params {
35*8226594fSRick McNeal 	uint32_t	mailbox[6];	/* mailboxes 0-5 */
36*8226594fSRick McNeal } __packed sis_sync_cmd_params_t;
37*8226594fSRick McNeal 
38*8226594fSRick McNeal #define	SIS_BASE_STRUCT_REVISION	9
39*8226594fSRick McNeal 
40*8226594fSRick McNeal typedef struct sis_base_struct {
41*8226594fSRick McNeal 	uint32_t	sb_revision;
42*8226594fSRick McNeal 	uint32_t	sb_flags;
43*8226594fSRick McNeal 	uint32_t	sb_error_buffer_paddr_low;
44*8226594fSRick McNeal 	uint32_t	sb_error_buffer_paddr_high;
45*8226594fSRick McNeal 	uint32_t	sb_error_elements_len;
46*8226594fSRick McNeal 	uint32_t	sb_error_elements_num;
47*8226594fSRick McNeal } __packed sis_base_struct_t;
48*8226594fSRick McNeal 
49*8226594fSRick McNeal /* ---- Forward declaration for support functions ---- */
50*8226594fSRick McNeal static boolean_t sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd,
51*8226594fSRick McNeal     sis_sync_cmd_params_t *params);
52*8226594fSRick McNeal 
53*8226594fSRick McNeal uint32_t
sis_read_scratch(pqi_state_t * s)54*8226594fSRick McNeal sis_read_scratch(pqi_state_t *s)
55*8226594fSRick McNeal {
56*8226594fSRick McNeal 	return (G32(s, sis_driver_scratch));
57*8226594fSRick McNeal }
58*8226594fSRick McNeal 
59*8226594fSRick McNeal void
sis_write_scratch(pqi_state_t * s,int mode)60*8226594fSRick McNeal sis_write_scratch(pqi_state_t *s, int mode)
61*8226594fSRick McNeal {
62*8226594fSRick McNeal 	S32(s, sis_driver_scratch, mode);
63*8226594fSRick McNeal }
64*8226594fSRick McNeal 
65*8226594fSRick McNeal boolean_t
sis_reenable_mode(pqi_state_t * s)66*8226594fSRick McNeal sis_reenable_mode(pqi_state_t *s)
67*8226594fSRick McNeal {
68*8226594fSRick McNeal 	int		loop_count;
69*8226594fSRick McNeal 	uint32_t	doorbell;
70*8226594fSRick McNeal 
71*8226594fSRick McNeal 	S32(s, sis_host_to_ctrl_doorbell, SIS_REENABLE_SIS_MODE);
72*8226594fSRick McNeal 
73*8226594fSRick McNeal 	for (loop_count = 0; loop_count < 1000; loop_count++) {
74*8226594fSRick McNeal 		doorbell = G32(s, sis_ctrl_to_host_doorbell);
75*8226594fSRick McNeal 		if ((doorbell & SIS_REENABLE_SIS_MODE) == 0) {
76*8226594fSRick McNeal 			return (B_TRUE);
77*8226594fSRick McNeal 		}
78*8226594fSRick McNeal 		drv_usecwait(MICROSEC / MILLISEC); /* ---- Wait 1ms ---- */
79*8226594fSRick McNeal 	}
80*8226594fSRick McNeal 	return (B_FALSE);
81*8226594fSRick McNeal }
82*8226594fSRick McNeal 
83*8226594fSRick McNeal boolean_t
sis_wait_for_ctrl_ready(pqi_state_t * s)84*8226594fSRick McNeal sis_wait_for_ctrl_ready(pqi_state_t *s)
85*8226594fSRick McNeal {
86*8226594fSRick McNeal 	int		loop_count;
87*8226594fSRick McNeal 	uint32_t	status;
88*8226594fSRick McNeal 
89*8226594fSRick McNeal 	for (loop_count = 0; loop_count < 1000; loop_count++) {
90*8226594fSRick McNeal 		status = G32(s, sis_firmware_status);
91*8226594fSRick McNeal 		if (status & SIS_CTRL_KERNEL_PANIC)
92*8226594fSRick McNeal 			return (B_FALSE);
93*8226594fSRick McNeal 		if (status & SIS_CTRL_KERNEL_UP)
94*8226594fSRick McNeal 			return (B_TRUE);
95*8226594fSRick McNeal 		drv_usecwait(MICROSEC / MILLISEC); /* ---- Wait 1ms ---- */
96*8226594fSRick McNeal 	}
97*8226594fSRick McNeal 	return (B_FALSE);
98*8226594fSRick McNeal }
99*8226594fSRick McNeal 
100*8226594fSRick McNeal /*
101*8226594fSRick McNeal  * sis_get_ctrl_props -- Verify we're talking to controller that speaks PQI
102*8226594fSRick McNeal  */
103*8226594fSRick McNeal boolean_t
sis_get_ctrl_props(pqi_state_t * s)104*8226594fSRick McNeal sis_get_ctrl_props(pqi_state_t *s)
105*8226594fSRick McNeal {
106*8226594fSRick McNeal 	sis_sync_cmd_params_t	p;
107*8226594fSRick McNeal 	uint32_t		property;
108*8226594fSRick McNeal 	uint32_t		extended_property;
109*8226594fSRick McNeal 
110*8226594fSRick McNeal 	(void) memset(&p, 0, sizeof (p));
111*8226594fSRick McNeal 	if (sis_send_sync_cmd(s, SIS_CMD_GET_ADAPTER_PROPERTIES, &p) == B_FALSE)
112*8226594fSRick McNeal 		return (B_FALSE);
113*8226594fSRick McNeal 
114*8226594fSRick McNeal 	property = p.mailbox[1];
115*8226594fSRick McNeal 	if (!(property & SIS_EXTENDED_PROPERTIES_SUPPORTED))
116*8226594fSRick McNeal 		return (B_FALSE);
117*8226594fSRick McNeal 
118*8226594fSRick McNeal 	extended_property = p.mailbox[4];
119*8226594fSRick McNeal 	if ((extended_property & SIS_REQUIRED_EXTENDED_PROPERTIES) !=
120*8226594fSRick McNeal 	    SIS_REQUIRED_EXTENDED_PROPERTIES)
121*8226594fSRick McNeal 		return (B_FALSE);
122*8226594fSRick McNeal 
123*8226594fSRick McNeal 	return (B_TRUE);
124*8226594fSRick McNeal }
125*8226594fSRick McNeal 
126*8226594fSRick McNeal boolean_t
sis_get_pqi_capabilities(pqi_state_t * s)127*8226594fSRick McNeal sis_get_pqi_capabilities(pqi_state_t *s)
128*8226594fSRick McNeal {
129*8226594fSRick McNeal 	sis_sync_cmd_params_t	p;
130*8226594fSRick McNeal 
131*8226594fSRick McNeal 	(void) memset(&p, 0, sizeof (p));
132*8226594fSRick McNeal 	if (sis_send_sync_cmd(s, SIS_CMD_GET_PQI_CAPABILITIES, &p) == B_FALSE)
133*8226594fSRick McNeal 		return (B_FALSE);
134*8226594fSRick McNeal 
135*8226594fSRick McNeal 	s->s_max_sg_entries = p.mailbox[1];
136*8226594fSRick McNeal 	s->s_max_xfer_size = p.mailbox[2];
137*8226594fSRick McNeal 	s->s_max_outstanding_requests = p.mailbox[3];
138*8226594fSRick McNeal 	s->s_config_table_offset = p.mailbox[4];
139*8226594fSRick McNeal 	s->s_config_table_len = p.mailbox[5];
140*8226594fSRick McNeal 	return (B_TRUE);
141*8226594fSRick McNeal }
142*8226594fSRick McNeal 
143*8226594fSRick McNeal boolean_t
sis_init_base_struct_addr(pqi_state_t * s)144*8226594fSRick McNeal sis_init_base_struct_addr(pqi_state_t *s)
145*8226594fSRick McNeal {
146*8226594fSRick McNeal 	sis_base_struct_t	*base;
147*8226594fSRick McNeal 	pqi_dma_overhead_t	*o;
148*8226594fSRick McNeal 	sis_sync_cmd_params_t	params;
149*8226594fSRick McNeal 	boolean_t		rc;
150*8226594fSRick McNeal 	void			*dma_addr;
151*8226594fSRick McNeal 
152*8226594fSRick McNeal 	o = pqi_alloc_single(s, sizeof (*base) + SIS_BASE_STRUCT_ALIGNMENT);
153*8226594fSRick McNeal 	if (o == NULL)
154*8226594fSRick McNeal 		return (B_FALSE);
155*8226594fSRick McNeal 
156*8226594fSRick McNeal 	base = PQIALIGN_TYPED(o->alloc_memory, SIS_BASE_STRUCT_ALIGNMENT,
157*8226594fSRick McNeal 	    sis_base_struct_t *);
158*8226594fSRick McNeal 	base->sb_revision = SIS_BASE_STRUCT_REVISION;
159*8226594fSRick McNeal 	base->sb_error_buffer_paddr_low = (uint32_t)s->s_error_dma->dma_addr;
160*8226594fSRick McNeal 	base->sb_error_buffer_paddr_high =
161*8226594fSRick McNeal 	    (uint32_t)(s->s_error_dma->dma_addr >> 32);
162*8226594fSRick McNeal 	base->sb_error_elements_len = PQI_ERROR_BUFFER_ELEMENT_LENGTH;
163*8226594fSRick McNeal 	base->sb_error_elements_num = s->s_max_outstanding_requests;
164*8226594fSRick McNeal 
165*8226594fSRick McNeal 	dma_addr = PQIALIGN_TYPED(o->dma_addr, SIS_BASE_STRUCT_ALIGNMENT,
166*8226594fSRick McNeal 	    void *);
167*8226594fSRick McNeal 	(void) memset(&params, 0, sizeof (params));
168*8226594fSRick McNeal 	params.mailbox[1] = (uint32_t)(uintptr_t)dma_addr;
169*8226594fSRick McNeal 	params.mailbox[2] = (uint32_t)((uint64_t)((uintptr_t)dma_addr) >> 32);
170*8226594fSRick McNeal 	params.mailbox[3] = sizeof (*base);
171*8226594fSRick McNeal 	(void) ddi_dma_sync(o->handle, 0, 0, DDI_DMA_SYNC_FORDEV);
172*8226594fSRick McNeal 	rc = sis_send_sync_cmd(s, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, &params);
173*8226594fSRick McNeal 
174*8226594fSRick McNeal 	pqi_free_single(s, o);
175*8226594fSRick McNeal 
176*8226594fSRick McNeal 	return (rc);
177*8226594fSRick McNeal }
178*8226594fSRick McNeal 
179*8226594fSRick McNeal /*
180*8226594fSRick McNeal  * Support functions for the visible legacy functions
181*8226594fSRick McNeal  */
182*8226594fSRick McNeal static boolean_t
sis_send_sync_cmd(pqi_state_t * s,uint32_t cmd,sis_sync_cmd_params_t * params)183*8226594fSRick McNeal sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd,
184*8226594fSRick McNeal     sis_sync_cmd_params_t *params)
185*8226594fSRick McNeal {
186*8226594fSRick McNeal 	uint32_t	i;
187*8226594fSRick McNeal 	uint32_t	doorbell;
188*8226594fSRick McNeal 	uint32_t	cmd_status;
189*8226594fSRick McNeal 
190*8226594fSRick McNeal 	/* Write the command to mailbox 0. */
191*8226594fSRick McNeal 	S32(s, sis_mailbox[0], cmd);
192*8226594fSRick McNeal 
193*8226594fSRick McNeal 	/*
194*8226594fSRick McNeal 	 * Write the command parameters to mailboxes 1-4 (mailbox 5 is not used
195*8226594fSRick McNeal 	 * when sending a command to the controller).
196*8226594fSRick McNeal 	 */
197*8226594fSRick McNeal 	for (i = 1; i <= 4; i++)
198*8226594fSRick McNeal 		S32(s, sis_mailbox[i], params->mailbox[i]);
199*8226594fSRick McNeal 
200*8226594fSRick McNeal 	/* Clear the command doorbell. */
201*8226594fSRick McNeal 	S32(s, sis_ctrl_to_host_doorbell_clear,
202*8226594fSRick McNeal 	    SIS_CLEAR_CTRL_TO_HOST_DOORBELL);
203*8226594fSRick McNeal 
204*8226594fSRick McNeal 	/* Disable doorbell interrupts by masking all interrupts. */
205*8226594fSRick McNeal 	S32(s, sis_interrupt_mask, ~0);
206*8226594fSRick McNeal 
207*8226594fSRick McNeal 	/*
208*8226594fSRick McNeal 	 * Force the completion of the interrupt mask register write before
209*8226594fSRick McNeal 	 * submitting the command.
210*8226594fSRick McNeal 	 */
211*8226594fSRick McNeal 	(void) G32(s, sis_interrupt_mask);
212*8226594fSRick McNeal 
213*8226594fSRick McNeal 	/* Submit the command to the controller. */
214*8226594fSRick McNeal 	S32(s, sis_host_to_ctrl_doorbell, SIS_CMD_READY);
215*8226594fSRick McNeal 
216*8226594fSRick McNeal 	/*
217*8226594fSRick McNeal 	 * Poll for command completion.  Note that the call to msleep() is at
218*8226594fSRick McNeal 	 * the top of the loop in order to give the controller time to start
219*8226594fSRick McNeal 	 * processing the command before we start polling.
220*8226594fSRick McNeal 	 */
221*8226594fSRick McNeal 	for (i = 0; i < 10000; i++) {
222*8226594fSRick McNeal 		drv_usecwait(MICROSEC / MILLISEC);
223*8226594fSRick McNeal 		doorbell = G32(s, sis_ctrl_to_host_doorbell);
224*8226594fSRick McNeal 		if (doorbell & SIS_CMD_COMPLETE)
225*8226594fSRick McNeal 			break;
226*8226594fSRick McNeal 	}
227*8226594fSRick McNeal 	if (i == 10000)
228*8226594fSRick McNeal 		return (B_FALSE);
229*8226594fSRick McNeal 
230*8226594fSRick McNeal 	/* Read the command status from mailbox 0. */
231*8226594fSRick McNeal 	cmd_status = G32(s, sis_mailbox[0]);
232*8226594fSRick McNeal 	if (cmd_status != SIS_CMD_STATUS_SUCCESS)
233*8226594fSRick McNeal 		return (B_FALSE);
234*8226594fSRick McNeal 
235*8226594fSRick McNeal 	/*
236*8226594fSRick McNeal 	 * The command completed successfully, so save the command status and
237*8226594fSRick McNeal 	 * read the values returned in mailboxes 1-5.
238*8226594fSRick McNeal 	 */
239*8226594fSRick McNeal 	params->mailbox[0] = cmd_status;
240*8226594fSRick McNeal 	for (i = 1; i < ARRAY_SIZE(params->mailbox); i++)
241*8226594fSRick McNeal 		params->mailbox[i] = G32(s, sis_mailbox[i]);
242*8226594fSRick McNeal 
243*8226594fSRick McNeal 	return (B_TRUE);
244*8226594fSRick McNeal }
245