esas2r_vda.c 13 KB

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