pm8001_ctl.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver
  3. *
  4. * Copyright (c) 2008-2009 USI Co., Ltd.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions, and the following disclaimer,
  12. * without modification.
  13. * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  14. * substantially similar to the "NO WARRANTY" disclaimer below
  15. * ("Disclaimer") and any redistribution must be conditioned upon
  16. * including a substantially similar Disclaimer requirement for further
  17. * binary redistribution.
  18. * 3. Neither the names of the above-listed copyright holders nor the names
  19. * of any contributors may be used to endorse or promote products derived
  20. * from this software without specific prior written permission.
  21. *
  22. * Alternatively, this software may be distributed under the terms of the
  23. * GNU General Public License ("GPL") version 2 as published by the Free
  24. * Software Foundation.
  25. *
  26. * NO WARRANTY
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  28. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  29. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  30. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  31. * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  33. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  34. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  35. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  36. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGES.
  38. *
  39. */
  40. #include <linux/firmware.h>
  41. #include <linux/slab.h>
  42. #include "pm8001_sas.h"
  43. #include "pm8001_ctl.h"
  44. /* scsi host attributes */
  45. /**
  46. * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number
  47. * @cdev: pointer to embedded class device
  48. * @buf: the buffer returned
  49. *
  50. * A sysfs 'read-only' shost attribute.
  51. */
  52. static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
  53. struct device_attribute *attr, char *buf)
  54. {
  55. struct Scsi_Host *shost = class_to_shost(cdev);
  56. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  57. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  58. if (pm8001_ha->chip_id == chip_8001) {
  59. return snprintf(buf, PAGE_SIZE, "%d\n",
  60. pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev);
  61. } else {
  62. return snprintf(buf, PAGE_SIZE, "%d\n",
  63. pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev);
  64. }
  65. }
  66. static
  67. DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
  68. /**
  69. * pm8001_ctl_fw_version_show - firmware version
  70. * @cdev: pointer to embedded class device
  71. * @buf: the buffer returned
  72. *
  73. * A sysfs 'read-only' shost attribute.
  74. */
  75. static ssize_t pm8001_ctl_fw_version_show(struct device *cdev,
  76. struct device_attribute *attr, char *buf)
  77. {
  78. struct Scsi_Host *shost = class_to_shost(cdev);
  79. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  80. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  81. if (pm8001_ha->chip_id == chip_8001) {
  82. return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
  83. (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24),
  84. (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16),
  85. (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8),
  86. (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev));
  87. } else {
  88. return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
  89. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24),
  90. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16),
  91. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8),
  92. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev));
  93. }
  94. }
  95. static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL);
  96. /**
  97. * pm8001_ctl_ila_version_show - ila version
  98. * @cdev: pointer to embedded class device
  99. * @buf: the buffer returned
  100. *
  101. * A sysfs 'read-only' shost attribute.
  102. */
  103. static ssize_t pm8001_ctl_ila_version_show(struct device *cdev,
  104. struct device_attribute *attr, char *buf)
  105. {
  106. struct Scsi_Host *shost = class_to_shost(cdev);
  107. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  108. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  109. if (pm8001_ha->chip_id != chip_8001) {
  110. return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
  111. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 24),
  112. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 16),
  113. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 8),
  114. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version));
  115. }
  116. return 0;
  117. }
  118. static DEVICE_ATTR(ila_version, 0444, pm8001_ctl_ila_version_show, NULL);
  119. /**
  120. * pm8001_ctl_inactive_fw_version_show - Inacative firmware version number
  121. * @cdev: pointer to embedded class device
  122. * @buf: the buffer returned
  123. *
  124. * A sysfs 'read-only' shost attribute.
  125. */
  126. static ssize_t pm8001_ctl_inactive_fw_version_show(struct device *cdev,
  127. struct device_attribute *attr, char *buf)
  128. {
  129. struct Scsi_Host *shost = class_to_shost(cdev);
  130. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  131. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  132. if (pm8001_ha->chip_id != chip_8001) {
  133. return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
  134. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 24),
  135. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 16),
  136. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 8),
  137. (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version));
  138. }
  139. return 0;
  140. }
  141. static
  142. DEVICE_ATTR(inc_fw_ver, 0444, pm8001_ctl_inactive_fw_version_show, NULL);
  143. /**
  144. * pm8001_ctl_max_out_io_show - max outstanding io supported
  145. * @cdev: pointer to embedded class device
  146. * @buf: the buffer returned
  147. *
  148. * A sysfs 'read-only' shost attribute.
  149. */
  150. static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev,
  151. struct device_attribute *attr, char *buf)
  152. {
  153. struct Scsi_Host *shost = class_to_shost(cdev);
  154. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  155. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  156. if (pm8001_ha->chip_id == chip_8001) {
  157. return snprintf(buf, PAGE_SIZE, "%d\n",
  158. pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io);
  159. } else {
  160. return snprintf(buf, PAGE_SIZE, "%d\n",
  161. pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io);
  162. }
  163. }
  164. static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL);
  165. /**
  166. * pm8001_ctl_max_devices_show - max devices support
  167. * @cdev: pointer to embedded class device
  168. * @buf: the buffer returned
  169. *
  170. * A sysfs 'read-only' shost attribute.
  171. */
  172. static ssize_t pm8001_ctl_max_devices_show(struct device *cdev,
  173. struct device_attribute *attr, char *buf)
  174. {
  175. struct Scsi_Host *shost = class_to_shost(cdev);
  176. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  177. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  178. if (pm8001_ha->chip_id == chip_8001) {
  179. return snprintf(buf, PAGE_SIZE, "%04d\n",
  180. (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16)
  181. );
  182. } else {
  183. return snprintf(buf, PAGE_SIZE, "%04d\n",
  184. (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16)
  185. );
  186. }
  187. }
  188. static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);
  189. /**
  190. * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no
  191. * hardware limitation
  192. * @cdev: pointer to embedded class device
  193. * @buf: the buffer returned
  194. *
  195. * A sysfs 'read-only' shost attribute.
  196. */
  197. static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,
  198. struct device_attribute *attr, char *buf)
  199. {
  200. struct Scsi_Host *shost = class_to_shost(cdev);
  201. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  202. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  203. if (pm8001_ha->chip_id == chip_8001) {
  204. return snprintf(buf, PAGE_SIZE, "%04d\n",
  205. pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF
  206. );
  207. } else {
  208. return snprintf(buf, PAGE_SIZE, "%04d\n",
  209. pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF
  210. );
  211. }
  212. }
  213. static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);
  214. #define SAS_1_0 0x1
  215. #define SAS_1_1 0x2
  216. #define SAS_2_0 0x4
  217. static ssize_t
  218. show_sas_spec_support_status(unsigned int mode, char *buf)
  219. {
  220. ssize_t len = 0;
  221. if (mode & SAS_1_1)
  222. len = sprintf(buf, "%s", "SAS1.1");
  223. if (mode & SAS_2_0)
  224. len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0");
  225. len += sprintf(buf + len, "\n");
  226. return len;
  227. }
  228. /**
  229. * pm8001_ctl_sas_spec_support_show - sas spec supported
  230. * @cdev: pointer to embedded class device
  231. * @buf: the buffer returned
  232. *
  233. * A sysfs 'read-only' shost attribute.
  234. */
  235. static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev,
  236. struct device_attribute *attr, char *buf)
  237. {
  238. unsigned int mode;
  239. struct Scsi_Host *shost = class_to_shost(cdev);
  240. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  241. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  242. /* fe000000 means supports SAS2.1 */
  243. if (pm8001_ha->chip_id == chip_8001)
  244. mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag &
  245. 0xfe000000)>>25;
  246. else
  247. /* fe000000 means supports SAS2.1 */
  248. mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag &
  249. 0xfe000000)>>25;
  250. return show_sas_spec_support_status(mode, buf);
  251. }
  252. static DEVICE_ATTR(sas_spec_support, S_IRUGO,
  253. pm8001_ctl_sas_spec_support_show, NULL);
  254. /**
  255. * pm8001_ctl_sas_address_show - sas address
  256. * @cdev: pointer to embedded class device
  257. * @buf: the buffer returned
  258. *
  259. * This is the controller sas address
  260. *
  261. * A sysfs 'read-only' shost attribute.
  262. */
  263. static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,
  264. struct device_attribute *attr, char *buf)
  265. {
  266. struct Scsi_Host *shost = class_to_shost(cdev);
  267. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  268. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  269. return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
  270. be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));
  271. }
  272. static DEVICE_ATTR(host_sas_address, S_IRUGO,
  273. pm8001_ctl_host_sas_address_show, NULL);
  274. /**
  275. * pm8001_ctl_logging_level_show - logging level
  276. * @cdev: pointer to embedded class device
  277. * @buf: the buffer returned
  278. *
  279. * A sysfs 'read/write' shost attribute.
  280. */
  281. static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,
  282. struct device_attribute *attr, char *buf)
  283. {
  284. struct Scsi_Host *shost = class_to_shost(cdev);
  285. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  286. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  287. return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level);
  288. }
  289. static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,
  290. struct device_attribute *attr, const char *buf, size_t count)
  291. {
  292. struct Scsi_Host *shost = class_to_shost(cdev);
  293. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  294. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  295. int val = 0;
  296. if (sscanf(buf, "%x", &val) != 1)
  297. return -EINVAL;
  298. pm8001_ha->logging_level = val;
  299. return strlen(buf);
  300. }
  301. static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
  302. pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);
  303. /**
  304. * pm8001_ctl_aap_log_show - aap1 event log
  305. * @cdev: pointer to embedded class device
  306. * @buf: the buffer returned
  307. *
  308. * A sysfs 'read-only' shost attribute.
  309. */
  310. static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
  311. struct device_attribute *attr, char *buf)
  312. {
  313. struct Scsi_Host *shost = class_to_shost(cdev);
  314. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  315. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  316. int i;
  317. #define AAP1_MEMMAP(r, c) \
  318. (*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32 \
  319. + (c)))
  320. char *str = buf;
  321. int max = 2;
  322. for (i = 0; i < max; i++) {
  323. str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
  324. "0x%08x 0x%08x\n",
  325. AAP1_MEMMAP(i, 0),
  326. AAP1_MEMMAP(i, 4),
  327. AAP1_MEMMAP(i, 8),
  328. AAP1_MEMMAP(i, 12),
  329. AAP1_MEMMAP(i, 16),
  330. AAP1_MEMMAP(i, 20),
  331. AAP1_MEMMAP(i, 24),
  332. AAP1_MEMMAP(i, 28));
  333. }
  334. return str - buf;
  335. }
  336. static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
  337. /**
  338. * pm8001_ctl_ib_queue_log_show - Out bound Queue log
  339. * @cdev:pointer to embedded class device
  340. * @buf: the buffer returned
  341. * A sysfs 'read-only' shost attribute.
  342. */
  343. static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
  344. struct device_attribute *attr, char *buf)
  345. {
  346. struct Scsi_Host *shost = class_to_shost(cdev);
  347. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  348. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  349. int offset;
  350. char *str = buf;
  351. int start = 0;
  352. #define IB_MEMMAP(c) \
  353. (*(u32 *)((u8 *)pm8001_ha-> \
  354. memoryMap.region[IB].virt_ptr + \
  355. pm8001_ha->evtlog_ib_offset + (c)))
  356. for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
  357. str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
  358. start = start + 4;
  359. }
  360. pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
  361. if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
  362. pm8001_ha->evtlog_ib_offset = 0;
  363. return str - buf;
  364. }
  365. static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
  366. /**
  367. * pm8001_ctl_ob_queue_log_show - Out bound Queue log
  368. * @cdev:pointer to embedded class device
  369. * @buf: the buffer returned
  370. * A sysfs 'read-only' shost attribute.
  371. */
  372. static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,
  373. struct device_attribute *attr, char *buf)
  374. {
  375. struct Scsi_Host *shost = class_to_shost(cdev);
  376. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  377. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  378. int offset;
  379. char *str = buf;
  380. int start = 0;
  381. #define OB_MEMMAP(c) \
  382. (*(u32 *)((u8 *)pm8001_ha-> \
  383. memoryMap.region[OB].virt_ptr + \
  384. pm8001_ha->evtlog_ob_offset + (c)))
  385. for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
  386. str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
  387. start = start + 4;
  388. }
  389. pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
  390. if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
  391. pm8001_ha->evtlog_ob_offset = 0;
  392. return str - buf;
  393. }
  394. static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
  395. /**
  396. * pm8001_ctl_bios_version_show - Bios version Display
  397. * @cdev:pointer to embedded class device
  398. * @buf:the buffer returned
  399. * A sysfs 'read-only' shost attribute.
  400. */
  401. static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
  402. struct device_attribute *attr, char *buf)
  403. {
  404. struct Scsi_Host *shost = class_to_shost(cdev);
  405. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  406. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  407. char *str = buf;
  408. int bios_index;
  409. DECLARE_COMPLETION_ONSTACK(completion);
  410. struct pm8001_ioctl_payload payload;
  411. pm8001_ha->nvmd_completion = &completion;
  412. payload.minor_function = 7;
  413. payload.offset = 0;
  414. payload.length = 4096;
  415. payload.func_specific = kzalloc(4096, GFP_KERNEL);
  416. if (!payload.func_specific)
  417. return -ENOMEM;
  418. if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) {
  419. kfree(payload.func_specific);
  420. return -ENOMEM;
  421. }
  422. wait_for_completion(&completion);
  423. for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT;
  424. bios_index++)
  425. str += sprintf(str, "%c",
  426. *(payload.func_specific+bios_index));
  427. kfree(payload.func_specific);
  428. return str - buf;
  429. }
  430. static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
  431. /**
  432. * pm8001_ctl_aap_log_show - IOP event log
  433. * @cdev: pointer to embedded class device
  434. * @buf: the buffer returned
  435. *
  436. * A sysfs 'read-only' shost attribute.
  437. */
  438. static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
  439. struct device_attribute *attr, char *buf)
  440. {
  441. struct Scsi_Host *shost = class_to_shost(cdev);
  442. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  443. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  444. #define IOP_MEMMAP(r, c) \
  445. (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
  446. + (c)))
  447. int i;
  448. char *str = buf;
  449. int max = 2;
  450. for (i = 0; i < max; i++) {
  451. str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
  452. "0x%08x 0x%08x\n",
  453. IOP_MEMMAP(i, 0),
  454. IOP_MEMMAP(i, 4),
  455. IOP_MEMMAP(i, 8),
  456. IOP_MEMMAP(i, 12),
  457. IOP_MEMMAP(i, 16),
  458. IOP_MEMMAP(i, 20),
  459. IOP_MEMMAP(i, 24),
  460. IOP_MEMMAP(i, 28));
  461. }
  462. return str - buf;
  463. }
  464. static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
  465. /**
  466. ** pm8001_ctl_fatal_log_show - fatal error logging
  467. ** @cdev:pointer to embedded class device
  468. ** @buf: the buffer returned
  469. **
  470. ** A sysfs 'read-only' shost attribute.
  471. **/
  472. static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
  473. struct device_attribute *attr, char *buf)
  474. {
  475. ssize_t count;
  476. count = pm80xx_get_fatal_dump(cdev, attr, buf);
  477. return count;
  478. }
  479. static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
  480. /**
  481. ** pm8001_ctl_gsm_log_show - gsm dump collection
  482. ** @cdev:pointer to embedded class device
  483. ** @buf: the buffer returned
  484. **A sysfs 'read-only' shost attribute.
  485. **/
  486. static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
  487. struct device_attribute *attr, char *buf)
  488. {
  489. ssize_t count;
  490. count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
  491. return count;
  492. }
  493. static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
  494. #define FLASH_CMD_NONE 0x00
  495. #define FLASH_CMD_UPDATE 0x01
  496. #define FLASH_CMD_SET_NVMD 0x02
  497. struct flash_command {
  498. u8 command[8];
  499. int code;
  500. };
  501. static struct flash_command flash_command_table[] =
  502. {
  503. {"set_nvmd", FLASH_CMD_SET_NVMD},
  504. {"update", FLASH_CMD_UPDATE},
  505. {"", FLASH_CMD_NONE} /* Last entry should be NULL. */
  506. };
  507. struct error_fw {
  508. char *reason;
  509. int err_code;
  510. };
  511. static struct error_fw flash_error_table[] =
  512. {
  513. {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE},
  514. {"image header mismatch", FLASH_UPDATE_HDR_ERR},
  515. {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR},
  516. {"image CRC Error", FLASH_UPDATE_CRC_ERR},
  517. {"image length Error.", FLASH_UPDATE_LENGTH_ERR},
  518. {"Failed to program flash chip", FLASH_UPDATE_HW_ERR},
  519. {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED},
  520. {"Flash update disabled.", FLASH_UPDATE_DISABLED},
  521. {"Flash in progress", FLASH_IN_PROGRESS},
  522. {"Image file size Error", FAIL_FILE_SIZE},
  523. {"Input parameter error", FAIL_PARAMETERS},
  524. {"Out of memory", FAIL_OUT_MEMORY},
  525. {"OK", 0} /* Last entry err_code = 0. */
  526. };
  527. static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
  528. {
  529. struct pm8001_ioctl_payload *payload;
  530. DECLARE_COMPLETION_ONSTACK(completion);
  531. u8 *ioctlbuffer;
  532. u32 ret;
  533. u32 length = 1024 * 5 + sizeof(*payload) - 1;
  534. if (pm8001_ha->fw_image->size > 4096) {
  535. pm8001_ha->fw_status = FAIL_FILE_SIZE;
  536. return -EFAULT;
  537. }
  538. ioctlbuffer = kzalloc(length, GFP_KERNEL);
  539. if (!ioctlbuffer) {
  540. pm8001_ha->fw_status = FAIL_OUT_MEMORY;
  541. return -ENOMEM;
  542. }
  543. payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
  544. memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
  545. pm8001_ha->fw_image->size);
  546. payload->length = pm8001_ha->fw_image->size;
  547. payload->id = 0;
  548. payload->minor_function = 0x1;
  549. pm8001_ha->nvmd_completion = &completion;
  550. ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
  551. if (ret) {
  552. pm8001_ha->fw_status = FAIL_OUT_MEMORY;
  553. goto out;
  554. }
  555. wait_for_completion(&completion);
  556. out:
  557. kfree(ioctlbuffer);
  558. return ret;
  559. }
  560. static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
  561. {
  562. struct pm8001_ioctl_payload *payload;
  563. DECLARE_COMPLETION_ONSTACK(completion);
  564. u8 *ioctlbuffer;
  565. struct fw_control_info *fwControl;
  566. u32 partitionSize, partitionSizeTmp;
  567. u32 loopNumber, loopcount;
  568. struct pm8001_fw_image_header *image_hdr;
  569. u32 sizeRead = 0;
  570. u32 ret = 0;
  571. u32 length = 1024 * 16 + sizeof(*payload) - 1;
  572. if (pm8001_ha->fw_image->size < 28) {
  573. pm8001_ha->fw_status = FAIL_FILE_SIZE;
  574. return -EFAULT;
  575. }
  576. ioctlbuffer = kzalloc(length, GFP_KERNEL);
  577. if (!ioctlbuffer) {
  578. pm8001_ha->fw_status = FAIL_OUT_MEMORY;
  579. return -ENOMEM;
  580. }
  581. image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
  582. while (sizeRead < pm8001_ha->fw_image->size) {
  583. partitionSizeTmp =
  584. *(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
  585. partitionSize = be32_to_cpu(partitionSizeTmp);
  586. loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,
  587. IOCTL_BUF_SIZE);
  588. for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
  589. payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
  590. payload->length = 1024*16;
  591. payload->id = 0;
  592. fwControl =
  593. (struct fw_control_info *)&payload->func_specific;
  594. fwControl->len = IOCTL_BUF_SIZE; /* IN */
  595. fwControl->size = partitionSize + HEADER_LEN;/* IN */
  596. fwControl->retcode = 0;/* OUT */
  597. fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */
  598. /* for the last chunk of data in case file size is not even with
  599. 4k, load only the rest*/
  600. if (((loopcount-loopNumber) == 1) &&
  601. ((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) {
  602. fwControl->len =
  603. (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
  604. memcpy((u8 *)fwControl->buffer,
  605. (u8 *)pm8001_ha->fw_image->data + sizeRead,
  606. (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE);
  607. sizeRead +=
  608. (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
  609. } else {
  610. memcpy((u8 *)fwControl->buffer,
  611. (u8 *)pm8001_ha->fw_image->data + sizeRead,
  612. IOCTL_BUF_SIZE);
  613. sizeRead += IOCTL_BUF_SIZE;
  614. }
  615. pm8001_ha->nvmd_completion = &completion;
  616. ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
  617. if (ret) {
  618. pm8001_ha->fw_status = FAIL_OUT_MEMORY;
  619. goto out;
  620. }
  621. wait_for_completion(&completion);
  622. if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {
  623. pm8001_ha->fw_status = fwControl->retcode;
  624. ret = -EFAULT;
  625. goto out;
  626. }
  627. }
  628. }
  629. out:
  630. kfree(ioctlbuffer);
  631. return ret;
  632. }
  633. static ssize_t pm8001_store_update_fw(struct device *cdev,
  634. struct device_attribute *attr,
  635. const char *buf, size_t count)
  636. {
  637. struct Scsi_Host *shost = class_to_shost(cdev);
  638. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  639. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  640. char *cmd_ptr, *filename_ptr;
  641. int res, i;
  642. int flash_command = FLASH_CMD_NONE;
  643. int ret;
  644. if (!capable(CAP_SYS_ADMIN))
  645. return -EACCES;
  646. /* this test protects us from running two flash processes at once,
  647. * so we should start with this test */
  648. if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)
  649. return -EINPROGRESS;
  650. pm8001_ha->fw_status = FLASH_IN_PROGRESS;
  651. cmd_ptr = kcalloc(count, 2, GFP_KERNEL);
  652. if (!cmd_ptr) {
  653. pm8001_ha->fw_status = FAIL_OUT_MEMORY;
  654. return -ENOMEM;
  655. }
  656. filename_ptr = cmd_ptr + count;
  657. res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
  658. if (res != 2) {
  659. pm8001_ha->fw_status = FAIL_PARAMETERS;
  660. ret = -EINVAL;
  661. goto out;
  662. }
  663. for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
  664. if (!memcmp(flash_command_table[i].command,
  665. cmd_ptr, strlen(cmd_ptr))) {
  666. flash_command = flash_command_table[i].code;
  667. break;
  668. }
  669. }
  670. if (flash_command == FLASH_CMD_NONE) {
  671. pm8001_ha->fw_status = FAIL_PARAMETERS;
  672. ret = -EINVAL;
  673. goto out;
  674. }
  675. ret = request_firmware(&pm8001_ha->fw_image,
  676. filename_ptr,
  677. pm8001_ha->dev);
  678. if (ret) {
  679. pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;
  680. goto out;
  681. }
  682. if (FLASH_CMD_UPDATE == flash_command)
  683. ret = pm8001_update_flash(pm8001_ha);
  684. else
  685. ret = pm8001_set_nvmd(pm8001_ha);
  686. release_firmware(pm8001_ha->fw_image);
  687. out:
  688. kfree(cmd_ptr);
  689. if (ret)
  690. return ret;
  691. pm8001_ha->fw_status = FLASH_OK;
  692. return count;
  693. }
  694. static ssize_t pm8001_show_update_fw(struct device *cdev,
  695. struct device_attribute *attr, char *buf)
  696. {
  697. int i;
  698. struct Scsi_Host *shost = class_to_shost(cdev);
  699. struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
  700. struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
  701. for (i = 0; flash_error_table[i].err_code != 0; i++) {
  702. if (flash_error_table[i].err_code == pm8001_ha->fw_status)
  703. break;
  704. }
  705. if (pm8001_ha->fw_status != FLASH_IN_PROGRESS)
  706. pm8001_ha->fw_status = FLASH_OK;
  707. return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
  708. flash_error_table[i].err_code,
  709. flash_error_table[i].reason);
  710. }
  711. static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,
  712. pm8001_show_update_fw, pm8001_store_update_fw);
  713. struct device_attribute *pm8001_host_attrs[] = {
  714. &dev_attr_interface_rev,
  715. &dev_attr_fw_version,
  716. &dev_attr_update_fw,
  717. &dev_attr_aap_log,
  718. &dev_attr_iop_log,
  719. &dev_attr_fatal_log,
  720. &dev_attr_gsm_log,
  721. &dev_attr_max_out_io,
  722. &dev_attr_max_devices,
  723. &dev_attr_max_sg_list,
  724. &dev_attr_sas_spec_support,
  725. &dev_attr_logging_level,
  726. &dev_attr_host_sas_address,
  727. &dev_attr_bios_version,
  728. &dev_attr_ib_log,
  729. &dev_attr_ob_log,
  730. &dev_attr_ila_version,
  731. &dev_attr_inc_fw_ver,
  732. NULL,
  733. };