diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_attr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 120 |
1 files changed, 76 insertions, 44 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e96d58ded57c..87f90c4f08e9 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off, | |||
16 | { | 16 | { |
17 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | 17 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, |
18 | struct device, kobj))); | 18 | struct device, kobj))); |
19 | char *rbuf = (char *)ha->fw_dump; | ||
19 | 20 | ||
20 | if (ha->fw_dump_reading == 0) | 21 | if (ha->fw_dump_reading == 0) |
21 | return 0; | 22 | return 0; |
22 | if (off > ha->fw_dump_buffer_len) | 23 | if (off > ha->fw_dump_len) |
23 | return 0; | 24 | return 0; |
24 | if (off + count > ha->fw_dump_buffer_len) | 25 | if (off + count > ha->fw_dump_len) |
25 | count = ha->fw_dump_buffer_len - off; | 26 | count = ha->fw_dump_len - off; |
26 | 27 | ||
27 | memcpy(buf, &ha->fw_dump_buffer[off], count); | 28 | memcpy(buf, &rbuf[off], count); |
28 | 29 | ||
29 | return (count); | 30 | return (count); |
30 | } | 31 | } |
@@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, | |||
36 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | 37 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, |
37 | struct device, kobj))); | 38 | struct device, kobj))); |
38 | int reading; | 39 | int reading; |
39 | uint32_t dump_size; | ||
40 | 40 | ||
41 | if (off != 0) | 41 | if (off != 0) |
42 | return (0); | 42 | return (0); |
@@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, | |||
44 | reading = simple_strtol(buf, NULL, 10); | 44 | reading = simple_strtol(buf, NULL, 10); |
45 | switch (reading) { | 45 | switch (reading) { |
46 | case 0: | 46 | case 0: |
47 | if (ha->fw_dump_reading == 1) { | 47 | if (!ha->fw_dump_reading) |
48 | qla_printk(KERN_INFO, ha, | 48 | break; |
49 | "Firmware dump cleared on (%ld).\n", ha->host_no); | ||
50 | 49 | ||
51 | vfree(ha->fw_dump_buffer); | 50 | qla_printk(KERN_INFO, ha, |
52 | ha->fw_dump_buffer = NULL; | 51 | "Firmware dump cleared on (%ld).\n", ha->host_no); |
53 | ha->fw_dump_reading = 0; | 52 | |
54 | ha->fw_dumped = 0; | 53 | ha->fw_dump_reading = 0; |
55 | } | 54 | ha->fw_dumped = 0; |
56 | break; | 55 | break; |
57 | case 1: | 56 | case 1: |
58 | if (ha->fw_dumped && !ha->fw_dump_reading) { | 57 | if (ha->fw_dumped && !ha->fw_dump_reading) { |
59 | ha->fw_dump_reading = 1; | 58 | ha->fw_dump_reading = 1; |
60 | 59 | ||
61 | if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) | ||
62 | dump_size = FW_DUMP_SIZE_24XX; | ||
63 | else { | ||
64 | dump_size = FW_DUMP_SIZE_1M; | ||
65 | if (ha->fw_memory_size < 0x20000) | ||
66 | dump_size = FW_DUMP_SIZE_128K; | ||
67 | else if (ha->fw_memory_size < 0x80000) | ||
68 | dump_size = FW_DUMP_SIZE_512K; | ||
69 | } | ||
70 | ha->fw_dump_buffer = (char *)vmalloc(dump_size); | ||
71 | if (ha->fw_dump_buffer == NULL) { | ||
72 | qla_printk(KERN_WARNING, ha, | ||
73 | "Unable to allocate memory for firmware " | ||
74 | "dump buffer (%d).\n", dump_size); | ||
75 | |||
76 | ha->fw_dump_reading = 0; | ||
77 | return (count); | ||
78 | } | ||
79 | qla_printk(KERN_INFO, ha, | 60 | qla_printk(KERN_INFO, ha, |
80 | "Firmware dump ready for read on (%ld).\n", | 61 | "Raw firmware dump ready for read on (%ld).\n", |
81 | ha->host_no); | 62 | ha->host_no); |
82 | memset(ha->fw_dump_buffer, 0, dump_size); | ||
83 | ha->isp_ops.ascii_fw_dump(ha); | ||
84 | ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer); | ||
85 | } | 63 | } |
86 | break; | 64 | break; |
65 | case 2: | ||
66 | qla2x00_alloc_fw_dump(ha); | ||
67 | break; | ||
87 | } | 68 | } |
88 | return (count); | 69 | return (count); |
89 | } | 70 | } |
@@ -313,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off, | |||
313 | if (!capable(CAP_SYS_ADMIN) || off != 0) | 294 | if (!capable(CAP_SYS_ADMIN) || off != 0) |
314 | return 0; | 295 | return 0; |
315 | 296 | ||
316 | if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) | ||
317 | return -ENOTSUPP; | ||
318 | |||
319 | /* Read NVRAM. */ | 297 | /* Read NVRAM. */ |
320 | spin_lock_irqsave(&ha->hardware_lock, flags); | 298 | spin_lock_irqsave(&ha->hardware_lock, flags); |
321 | ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size); | 299 | ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size); |
@@ -335,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off, | |||
335 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) | 313 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) |
336 | return 0; | 314 | return 0; |
337 | 315 | ||
338 | if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) | ||
339 | return -ENOTSUPP; | ||
340 | |||
341 | /* Write NVRAM. */ | 316 | /* Write NVRAM. */ |
342 | spin_lock_irqsave(&ha->hardware_lock, flags); | 317 | spin_lock_irqsave(&ha->hardware_lock, flags); |
343 | ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count); | 318 | ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count); |
@@ -357,6 +332,53 @@ static struct bin_attribute sysfs_vpd_attr = { | |||
357 | .write = qla2x00_sysfs_write_vpd, | 332 | .write = qla2x00_sysfs_write_vpd, |
358 | }; | 333 | }; |
359 | 334 | ||
335 | static ssize_t | ||
336 | qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off, | ||
337 | size_t count) | ||
338 | { | ||
339 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | ||
340 | struct device, kobj))); | ||
341 | uint16_t iter, addr, offset; | ||
342 | int rval; | ||
343 | |||
344 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) | ||
345 | return 0; | ||
346 | |||
347 | addr = 0xa0; | ||
348 | for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; | ||
349 | iter++, offset += SFP_BLOCK_SIZE) { | ||
350 | if (iter == 4) { | ||
351 | /* Skip to next device address. */ | ||
352 | addr = 0xa2; | ||
353 | offset = 0; | ||
354 | } | ||
355 | |||
356 | rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset, | ||
357 | SFP_BLOCK_SIZE); | ||
358 | if (rval != QLA_SUCCESS) { | ||
359 | qla_printk(KERN_WARNING, ha, | ||
360 | "Unable to read SFP data (%x/%x/%x).\n", rval, | ||
361 | addr, offset); | ||
362 | count = 0; | ||
363 | break; | ||
364 | } | ||
365 | memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE); | ||
366 | buf += SFP_BLOCK_SIZE; | ||
367 | } | ||
368 | |||
369 | return count; | ||
370 | } | ||
371 | |||
372 | static struct bin_attribute sysfs_sfp_attr = { | ||
373 | .attr = { | ||
374 | .name = "sfp", | ||
375 | .mode = S_IRUSR | S_IWUSR, | ||
376 | .owner = THIS_MODULE, | ||
377 | }, | ||
378 | .size = SFP_DEV_SIZE * 2, | ||
379 | .read = qla2x00_sysfs_read_sfp, | ||
380 | }; | ||
381 | |||
360 | void | 382 | void |
361 | qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) | 383 | qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) |
362 | { | 384 | { |
@@ -367,7 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) | |||
367 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); | 389 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); |
368 | sysfs_create_bin_file(&host->shost_gendev.kobj, | 390 | sysfs_create_bin_file(&host->shost_gendev.kobj, |
369 | &sysfs_optrom_ctl_attr); | 391 | &sysfs_optrom_ctl_attr); |
370 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); | 392 | if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { |
393 | sysfs_create_bin_file(&host->shost_gendev.kobj, | ||
394 | &sysfs_vpd_attr); | ||
395 | sysfs_create_bin_file(&host->shost_gendev.kobj, | ||
396 | &sysfs_sfp_attr); | ||
397 | } | ||
371 | } | 398 | } |
372 | 399 | ||
373 | void | 400 | void |
@@ -380,7 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) | |||
380 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); | 407 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); |
381 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | 408 | sysfs_remove_bin_file(&host->shost_gendev.kobj, |
382 | &sysfs_optrom_ctl_attr); | 409 | &sysfs_optrom_ctl_attr); |
383 | sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); | 410 | if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { |
411 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | ||
412 | &sysfs_vpd_attr); | ||
413 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | ||
414 | &sysfs_sfp_attr); | ||
415 | } | ||
384 | 416 | ||
385 | if (ha->beacon_blink_led == 1) | 417 | if (ha->beacon_blink_led == 1) |
386 | ha->isp_ops.beacon_off(ha); | 418 | ha->isp_ops.beacon_off(ha); |