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