1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * linux/drivers/scsi/esas2r/esas2r_vda.c
3*4882a593Smuzhiyun * esas2r driver VDA firmware interface functions
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2001-2013 ATTO Technology, Inc.
6*4882a593Smuzhiyun * (mailto:linuxdrivers@attotech.com)
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
11*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
12*4882a593Smuzhiyun * the Free Software Foundation; version 2 of the License.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
15*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17*4882a593Smuzhiyun * GNU General Public License for more details.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * NO WARRANTY
20*4882a593Smuzhiyun * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
21*4882a593Smuzhiyun * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
22*4882a593Smuzhiyun * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
23*4882a593Smuzhiyun * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
24*4882a593Smuzhiyun * solely responsible for determining the appropriateness of using and
25*4882a593Smuzhiyun * distributing the Program and assumes all risks associated with its
26*4882a593Smuzhiyun * exercise of rights under this Agreement, including but not limited to
27*4882a593Smuzhiyun * the risks and costs of program errors, damage to or loss of data,
28*4882a593Smuzhiyun * programs or equipment, and unavailability or interruption of operations.
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * DISCLAIMER OF LIABILITY
31*4882a593Smuzhiyun * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
32*4882a593Smuzhiyun * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*4882a593Smuzhiyun * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
34*4882a593Smuzhiyun * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
35*4882a593Smuzhiyun * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36*4882a593Smuzhiyun * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
37*4882a593Smuzhiyun * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
38*4882a593Smuzhiyun *
39*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
40*4882a593Smuzhiyun * along with this program; if not, write to the Free Software
41*4882a593Smuzhiyun * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #include "esas2r.h"
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static u8 esas2r_vdaioctl_versions[] = {
48*4882a593Smuzhiyun ATTO_VDA_VER_UNSUPPORTED,
49*4882a593Smuzhiyun ATTO_VDA_FLASH_VER,
50*4882a593Smuzhiyun ATTO_VDA_VER_UNSUPPORTED,
51*4882a593Smuzhiyun ATTO_VDA_VER_UNSUPPORTED,
52*4882a593Smuzhiyun ATTO_VDA_CLI_VER,
53*4882a593Smuzhiyun ATTO_VDA_VER_UNSUPPORTED,
54*4882a593Smuzhiyun ATTO_VDA_CFG_VER,
55*4882a593Smuzhiyun ATTO_VDA_MGT_VER,
56*4882a593Smuzhiyun ATTO_VDA_GSV_VER
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static void clear_vda_request(struct esas2r_request *rq);
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
62*4882a593Smuzhiyun struct esas2r_request *rq);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* Prepare a VDA IOCTL request to be sent to the firmware. */
esas2r_process_vda_ioctl(struct esas2r_adapter * a,struct atto_ioctl_vda * vi,struct esas2r_request * rq,struct esas2r_sg_context * sgc)65*4882a593Smuzhiyun bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
66*4882a593Smuzhiyun struct atto_ioctl_vda *vi,
67*4882a593Smuzhiyun struct esas2r_request *rq,
68*4882a593Smuzhiyun struct esas2r_sg_context *sgc)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun u32 datalen = 0;
71*4882a593Smuzhiyun struct atto_vda_sge *firstsg = NULL;
72*4882a593Smuzhiyun u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun vi->status = ATTO_STS_SUCCESS;
75*4882a593Smuzhiyun vi->vda_status = RS_PENDING;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (vi->function >= vercnt) {
78*4882a593Smuzhiyun vi->status = ATTO_STS_INV_FUNC;
79*4882a593Smuzhiyun return false;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
83*4882a593Smuzhiyun vi->status = ATTO_STS_INV_VERSION;
84*4882a593Smuzhiyun return false;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
88*4882a593Smuzhiyun vi->status = ATTO_STS_DEGRADED;
89*4882a593Smuzhiyun return false;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (vi->function != VDA_FUNC_SCSI)
93*4882a593Smuzhiyun clear_vda_request(rq);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun rq->vrq->scsi.function = vi->function;
96*4882a593Smuzhiyun rq->interrupt_cb = esas2r_complete_vda_ioctl;
97*4882a593Smuzhiyun rq->interrupt_cx = vi;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun switch (vi->function) {
100*4882a593Smuzhiyun case VDA_FUNC_FLASH:
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
103*4882a593Smuzhiyun && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
104*4882a593Smuzhiyun && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
105*4882a593Smuzhiyun vi->status = ATTO_STS_INV_FUNC;
106*4882a593Smuzhiyun return false;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
110*4882a593Smuzhiyun datalen = vi->data_length;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun rq->vrq->flash.length = cpu_to_le32(datalen);
113*4882a593Smuzhiyun rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun memcpy(rq->vrq->flash.data.file.file_name,
116*4882a593Smuzhiyun vi->cmd.flash.data.file.file_name,
117*4882a593Smuzhiyun sizeof(vi->cmd.flash.data.file.file_name));
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun firstsg = rq->vrq->flash.data.file.sge;
120*4882a593Smuzhiyun break;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun case VDA_FUNC_CLI:
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun datalen = vi->data_length;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun rq->vrq->cli.cmd_rsp_len =
127*4882a593Smuzhiyun cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
128*4882a593Smuzhiyun rq->vrq->cli.length = cpu_to_le32(datalen);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun firstsg = rq->vrq->cli.sge;
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun case VDA_FUNC_MGT:
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun u8 *cmdcurr_offset = sgc->cur_offset
136*4882a593Smuzhiyun - offsetof(struct atto_ioctl_vda, data)
137*4882a593Smuzhiyun + offsetof(struct atto_ioctl_vda, cmd)
138*4882a593Smuzhiyun + offsetof(struct atto_ioctl_vda_mgt_cmd,
139*4882a593Smuzhiyun data);
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun * build the data payload SGL here first since
142*4882a593Smuzhiyun * esas2r_sgc_init() will modify the S/G list offset for the
143*4882a593Smuzhiyun * management SGL (which is built below where the data SGL is
144*4882a593Smuzhiyun * usually built).
145*4882a593Smuzhiyun */
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun if (vi->data_length) {
148*4882a593Smuzhiyun u32 payldlen = 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
151*4882a593Smuzhiyun || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
152*4882a593Smuzhiyun rq->vrq->mgt.payld_sglst_offset =
153*4882a593Smuzhiyun (u8)offsetof(struct atto_vda_mgmt_req,
154*4882a593Smuzhiyun payld_sge);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun payldlen = vi->data_length;
157*4882a593Smuzhiyun datalen = vi->cmd.mgt.data_length;
158*4882a593Smuzhiyun } else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
159*4882a593Smuzhiyun || vi->cmd.mgt.mgt_func ==
160*4882a593Smuzhiyun VDAMGT_DEV_INFO2_BYADDR) {
161*4882a593Smuzhiyun datalen = vi->data_length;
162*4882a593Smuzhiyun cmdcurr_offset = sgc->cur_offset;
163*4882a593Smuzhiyun } else {
164*4882a593Smuzhiyun vi->status = ATTO_STS_INV_PARAM;
165*4882a593Smuzhiyun return false;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* Setup the length so building the payload SGL works */
169*4882a593Smuzhiyun rq->vrq->mgt.length = cpu_to_le32(datalen);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (payldlen) {
172*4882a593Smuzhiyun rq->vrq->mgt.payld_length =
173*4882a593Smuzhiyun cpu_to_le32(payldlen);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun esas2r_sgc_init(sgc, a, rq,
176*4882a593Smuzhiyun rq->vrq->mgt.payld_sge);
177*4882a593Smuzhiyun sgc->length = payldlen;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (!esas2r_build_sg_list(a, rq, sgc)) {
180*4882a593Smuzhiyun vi->status = ATTO_STS_OUT_OF_RSRC;
181*4882a593Smuzhiyun return false;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun } else {
185*4882a593Smuzhiyun datalen = vi->cmd.mgt.data_length;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun rq->vrq->mgt.length = cpu_to_le32(datalen);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * Now that the payload SGL is built, if any, setup to build
192*4882a593Smuzhiyun * the management SGL.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun firstsg = rq->vrq->mgt.sge;
195*4882a593Smuzhiyun sgc->cur_offset = cmdcurr_offset;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* Finish initializing the management request. */
198*4882a593Smuzhiyun rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
199*4882a593Smuzhiyun rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
200*4882a593Smuzhiyun rq->vrq->mgt.dev_index =
201*4882a593Smuzhiyun cpu_to_le32(vi->cmd.mgt.dev_index);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
204*4882a593Smuzhiyun break;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun case VDA_FUNC_CFG:
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun if (vi->data_length
210*4882a593Smuzhiyun || vi->cmd.cfg.data_length == 0) {
211*4882a593Smuzhiyun vi->status = ATTO_STS_INV_PARAM;
212*4882a593Smuzhiyun return false;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
216*4882a593Smuzhiyun vi->status = ATTO_STS_INV_FUNC;
217*4882a593Smuzhiyun return false;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
221*4882a593Smuzhiyun rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
224*4882a593Smuzhiyun memcpy(&rq->vrq->cfg.data,
225*4882a593Smuzhiyun &vi->cmd.cfg.data,
226*4882a593Smuzhiyun vi->cmd.cfg.data_length);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
229*4882a593Smuzhiyun &rq->vrq->cfg.data);
230*4882a593Smuzhiyun } else {
231*4882a593Smuzhiyun vi->status = ATTO_STS_INV_FUNC;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun return false;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun break;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun case VDA_FUNC_GSV:
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun vi->cmd.gsv.rsp_len = vercnt;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
243*4882a593Smuzhiyun vercnt);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun vi->vda_status = RS_SUCCESS;
246*4882a593Smuzhiyun break;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun default:
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun vi->status = ATTO_STS_INV_FUNC;
251*4882a593Smuzhiyun return false;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if (datalen) {
255*4882a593Smuzhiyun esas2r_sgc_init(sgc, a, rq, firstsg);
256*4882a593Smuzhiyun sgc->length = datalen;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (!esas2r_build_sg_list(a, rq, sgc)) {
259*4882a593Smuzhiyun vi->status = ATTO_STS_OUT_OF_RSRC;
260*4882a593Smuzhiyun return false;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun esas2r_start_request(a, rq);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return true;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
esas2r_complete_vda_ioctl(struct esas2r_adapter * a,struct esas2r_request * rq)269*4882a593Smuzhiyun static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
270*4882a593Smuzhiyun struct esas2r_request *rq)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun vi->vda_status = rq->req_stat;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun switch (vi->function) {
277*4882a593Smuzhiyun case VDA_FUNC_FLASH:
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
280*4882a593Smuzhiyun || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
281*4882a593Smuzhiyun vi->cmd.flash.data.file.file_size =
282*4882a593Smuzhiyun le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun break;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun case VDA_FUNC_MGT:
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun vi->cmd.mgt.scan_generation =
289*4882a593Smuzhiyun rq->func_rsp.mgt_rsp.scan_generation;
290*4882a593Smuzhiyun vi->cmd.mgt.dev_index = le16_to_cpu(
291*4882a593Smuzhiyun rq->func_rsp.mgt_rsp.dev_index);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (vi->data_length == 0)
294*4882a593Smuzhiyun vi->cmd.mgt.data_length =
295*4882a593Smuzhiyun le32_to_cpu(rq->func_rsp.mgt_rsp.length);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun case VDA_FUNC_CFG:
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
303*4882a593Smuzhiyun struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
304*4882a593Smuzhiyun struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
305*4882a593Smuzhiyun char buf[sizeof(cfg->data.init.fw_release) + 1];
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun cfg->data_length =
308*4882a593Smuzhiyun cpu_to_le32(sizeof(struct atto_vda_cfg_init));
309*4882a593Smuzhiyun cfg->data.init.vda_version =
310*4882a593Smuzhiyun le32_to_cpu(rsp->vda_version);
311*4882a593Smuzhiyun cfg->data.init.fw_build = rsp->fw_build;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun snprintf(buf, sizeof(buf), "%1.1u.%2.2u",
314*4882a593Smuzhiyun (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
315*4882a593Smuzhiyun (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun memcpy(&cfg->data.init.fw_release, buf,
318*4882a593Smuzhiyun sizeof(cfg->data.init.fw_release));
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
321*4882a593Smuzhiyun cfg->data.init.fw_version =
322*4882a593Smuzhiyun cfg->data.init.fw_build;
323*4882a593Smuzhiyun else
324*4882a593Smuzhiyun cfg->data.init.fw_version =
325*4882a593Smuzhiyun cfg->data.init.fw_release;
326*4882a593Smuzhiyun } else {
327*4882a593Smuzhiyun esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
328*4882a593Smuzhiyun &vi->cmd.cfg.data);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun case VDA_FUNC_CLI:
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun vi->cmd.cli.cmd_rsp_len =
336*4882a593Smuzhiyun le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun default:
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun break;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /* Build a flash VDA request. */
esas2r_build_flash_req(struct esas2r_adapter * a,struct esas2r_request * rq,u8 sub_func,u8 cksum,u32 addr,u32 length)346*4882a593Smuzhiyun void esas2r_build_flash_req(struct esas2r_adapter *a,
347*4882a593Smuzhiyun struct esas2r_request *rq,
348*4882a593Smuzhiyun u8 sub_func,
349*4882a593Smuzhiyun u8 cksum,
350*4882a593Smuzhiyun u32 addr,
351*4882a593Smuzhiyun u32 length)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct atto_vda_flash_req *vrq = &rq->vrq->flash;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun clear_vda_request(rq);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_FLASH;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (sub_func == VDA_FLASH_BEGINW
360*4882a593Smuzhiyun || sub_func == VDA_FLASH_WRITE
361*4882a593Smuzhiyun || sub_func == VDA_FLASH_READ)
362*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
363*4882a593Smuzhiyun data.sge);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun vrq->length = cpu_to_le32(length);
366*4882a593Smuzhiyun vrq->flash_addr = cpu_to_le32(addr);
367*4882a593Smuzhiyun vrq->checksum = cksum;
368*4882a593Smuzhiyun vrq->sub_func = sub_func;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun /* Build a VDA management request. */
esas2r_build_mgt_req(struct esas2r_adapter * a,struct esas2r_request * rq,u8 sub_func,u8 scan_gen,u16 dev_index,u32 length,void * data)372*4882a593Smuzhiyun void esas2r_build_mgt_req(struct esas2r_adapter *a,
373*4882a593Smuzhiyun struct esas2r_request *rq,
374*4882a593Smuzhiyun u8 sub_func,
375*4882a593Smuzhiyun u8 scan_gen,
376*4882a593Smuzhiyun u16 dev_index,
377*4882a593Smuzhiyun u32 length,
378*4882a593Smuzhiyun void *data)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun clear_vda_request(rq);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_MGT;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun vrq->mgt_func = sub_func;
387*4882a593Smuzhiyun vrq->scan_generation = scan_gen;
388*4882a593Smuzhiyun vrq->dev_index = cpu_to_le16(dev_index);
389*4882a593Smuzhiyun vrq->length = cpu_to_le32(length);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if (vrq->length) {
392*4882a593Smuzhiyun if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
393*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(
394*4882a593Smuzhiyun struct atto_vda_mgmt_req, sge);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
397*4882a593Smuzhiyun vrq->sge[0].address = cpu_to_le64(
398*4882a593Smuzhiyun rq->vrq_md->phys_addr +
399*4882a593Smuzhiyun sizeof(union atto_vda_req));
400*4882a593Smuzhiyun } else {
401*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(
402*4882a593Smuzhiyun struct atto_vda_mgmt_req, prde);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun vrq->prde[0].ctl_len = cpu_to_le32(length);
405*4882a593Smuzhiyun vrq->prde[0].address = cpu_to_le64(
406*4882a593Smuzhiyun rq->vrq_md->phys_addr +
407*4882a593Smuzhiyun sizeof(union atto_vda_req));
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (data) {
412*4882a593Smuzhiyun esas2r_nuxi_mgt_data(sub_func, data);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
415*4882a593Smuzhiyun length);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /* Build a VDA asyncronous event (AE) request. */
esas2r_build_ae_req(struct esas2r_adapter * a,struct esas2r_request * rq)420*4882a593Smuzhiyun void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun struct atto_vda_ae_req *vrq = &rq->vrq->ae;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun clear_vda_request(rq);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_AE;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
431*4882a593Smuzhiyun vrq->sg_list_offset =
432*4882a593Smuzhiyun (u8)offsetof(struct atto_vda_ae_req, sge);
433*4882a593Smuzhiyun vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
434*4882a593Smuzhiyun vrq->sge[0].address = cpu_to_le64(
435*4882a593Smuzhiyun rq->vrq_md->phys_addr +
436*4882a593Smuzhiyun sizeof(union atto_vda_req));
437*4882a593Smuzhiyun } else {
438*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
439*4882a593Smuzhiyun prde);
440*4882a593Smuzhiyun vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
441*4882a593Smuzhiyun vrq->prde[0].address = cpu_to_le64(
442*4882a593Smuzhiyun rq->vrq_md->phys_addr +
443*4882a593Smuzhiyun sizeof(union atto_vda_req));
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /* Build a VDA CLI request. */
esas2r_build_cli_req(struct esas2r_adapter * a,struct esas2r_request * rq,u32 length,u32 cmd_rsp_len)448*4882a593Smuzhiyun void esas2r_build_cli_req(struct esas2r_adapter *a,
449*4882a593Smuzhiyun struct esas2r_request *rq,
450*4882a593Smuzhiyun u32 length,
451*4882a593Smuzhiyun u32 cmd_rsp_len)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun struct atto_vda_cli_req *vrq = &rq->vrq->cli;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun clear_vda_request(rq);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_CLI;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun vrq->length = cpu_to_le32(length);
460*4882a593Smuzhiyun vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
461*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun /* Build a VDA IOCTL request. */
esas2r_build_ioctl_req(struct esas2r_adapter * a,struct esas2r_request * rq,u32 length,u8 sub_func)465*4882a593Smuzhiyun void esas2r_build_ioctl_req(struct esas2r_adapter *a,
466*4882a593Smuzhiyun struct esas2r_request *rq,
467*4882a593Smuzhiyun u32 length,
468*4882a593Smuzhiyun u8 sub_func)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun clear_vda_request(rq);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_IOCTL;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun vrq->length = cpu_to_le32(length);
477*4882a593Smuzhiyun vrq->sub_func = sub_func;
478*4882a593Smuzhiyun vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /* Build a VDA configuration request. */
esas2r_build_cfg_req(struct esas2r_adapter * a,struct esas2r_request * rq,u8 sub_func,u32 length,void * data)482*4882a593Smuzhiyun void esas2r_build_cfg_req(struct esas2r_adapter *a,
483*4882a593Smuzhiyun struct esas2r_request *rq,
484*4882a593Smuzhiyun u8 sub_func,
485*4882a593Smuzhiyun u32 length,
486*4882a593Smuzhiyun void *data)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun clear_vda_request(rq);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun rq->vrq->scsi.function = VDA_FUNC_CFG;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun vrq->sub_func = sub_func;
495*4882a593Smuzhiyun vrq->length = cpu_to_le32(length);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (data) {
498*4882a593Smuzhiyun esas2r_nuxi_cfg_data(sub_func, data);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun memcpy(&vrq->data, data, length);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
clear_vda_request(struct esas2r_request * rq)504*4882a593Smuzhiyun static void clear_vda_request(struct esas2r_request *rq)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun u32 handle = rq->vrq->scsi.handle;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun memset(rq->vrq, 0, sizeof(*rq->vrq));
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun rq->vrq->scsi.handle = handle;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun rq->req_stat = RS_PENDING;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* since the data buffer is separate clear that too */
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * Setup next and prev pointer in case the request is not going through
520*4882a593Smuzhiyun * esas2r_start_request().
521*4882a593Smuzhiyun */
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun INIT_LIST_HEAD(&rq->req_list);
524*4882a593Smuzhiyun }
525