1 /* 2 ******************************************************************************* 3 ** O.S : Linux 4 ** FILE NAME : arcmsr_attr.c 5 ** BY : Nick Cheng 6 ** Description: attributes exported to sysfs and device host 7 ******************************************************************************* 8 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved 9 ** 10 ** Web site: www.areca.com.tw 11 ** E-mail: support@areca.com.tw 12 ** 13 ** This program is free software; you can redistribute it and/or modify 14 ** it under the terms of the GNU General Public License version 2 as 15 ** published by the Free Software Foundation. 16 ** This program is distributed in the hope that it will be useful, 17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 ** GNU General Public License for more details. 20 ******************************************************************************* 21 ** Redistribution and use in source and binary forms, with or without 22 ** modification, are permitted provided that the following conditions 23 ** are met: 24 ** 1. Redistributions of source code must retain the above copyright 25 ** notice, this list of conditions and the following disclaimer. 26 ** 2. Redistributions in binary form must reproduce the above copyright 27 ** notice, this list of conditions and the following disclaimer in the 28 ** documentation and/or other materials provided with the distribution. 29 ** 3. The name of the author may not be used to endorse or promote products 30 ** derived from this software without specific prior written permission. 31 ** 32 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 33 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 34 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 35 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 36 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT 37 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY 39 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 ** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF 41 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 ******************************************************************************* 43 ** For history of changes, see Documentation/scsi/ChangeLog.arcmsr 44 ** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt 45 ******************************************************************************* 46 */ 47 #include <linux/module.h> 48 #include <linux/kernel.h> 49 #include <linux/init.h> 50 #include <linux/errno.h> 51 #include <linux/delay.h> 52 #include <linux/pci.h> 53 #include <linux/circ_buf.h> 54 55 #include <scsi/scsi_cmnd.h> 56 #include <scsi/scsi_device.h> 57 #include <scsi/scsi_host.h> 58 #include <scsi/scsi_transport.h> 59 #include "arcmsr.h" 60 61 struct device_attribute *arcmsr_host_attrs[]; 62 63 static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, 64 struct kobject *kobj, 65 struct bin_attribute *bin, 66 char *buf, loff_t off, 67 size_t count) 68 { 69 struct device *dev = container_of(kobj,struct device,kobj); 70 struct Scsi_Host *host = class_to_shost(dev); 71 struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; 72 uint8_t *ptmpQbuffer; 73 int32_t allxfer_len = 0; 74 unsigned long flags; 75 76 if (!capable(CAP_SYS_ADMIN)) 77 return -EACCES; 78 79 /* do message unit read. */ 80 ptmpQbuffer = (uint8_t *)buf; 81 spin_lock_irqsave(&acb->rqbuffer_lock, flags); 82 if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) { 83 unsigned int tail = acb->rqbuf_getIndex; 84 unsigned int head = acb->rqbuf_putIndex; 85 unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER); 86 87 allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER); 88 if (allxfer_len > ARCMSR_API_DATA_BUFLEN) 89 allxfer_len = ARCMSR_API_DATA_BUFLEN; 90 91 if (allxfer_len <= cnt_to_end) 92 memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len); 93 else { 94 memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end); 95 memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end); 96 } 97 acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER; 98 } 99 if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { 100 struct QBUFFER __iomem *prbuffer; 101 acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; 102 prbuffer = arcmsr_get_iop_rqbuffer(acb); 103 if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) 104 acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; 105 } 106 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); 107 return allxfer_len; 108 } 109 110 static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, 111 struct kobject *kobj, 112 struct bin_attribute *bin, 113 char *buf, loff_t off, 114 size_t count) 115 { 116 struct device *dev = container_of(kobj,struct device,kobj); 117 struct Scsi_Host *host = class_to_shost(dev); 118 struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; 119 int32_t user_len, cnt2end; 120 uint8_t *pQbuffer, *ptmpuserbuffer; 121 unsigned long flags; 122 123 if (!capable(CAP_SYS_ADMIN)) 124 return -EACCES; 125 if (count > ARCMSR_API_DATA_BUFLEN) 126 return -EINVAL; 127 /* do message unit write. */ 128 ptmpuserbuffer = (uint8_t *)buf; 129 user_len = (int32_t)count; 130 spin_lock_irqsave(&acb->wqbuffer_lock, flags); 131 if (acb->wqbuf_putIndex != acb->wqbuf_getIndex) { 132 arcmsr_write_ioctldata2iop(acb); 133 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); 134 return 0; /*need retry*/ 135 } else { 136 pQbuffer = &acb->wqbuffer[acb->wqbuf_putIndex]; 137 cnt2end = ARCMSR_MAX_QBUFFER - acb->wqbuf_putIndex; 138 if (user_len > cnt2end) { 139 memcpy(pQbuffer, ptmpuserbuffer, cnt2end); 140 ptmpuserbuffer += cnt2end; 141 user_len -= cnt2end; 142 acb->wqbuf_putIndex = 0; 143 pQbuffer = acb->wqbuffer; 144 } 145 memcpy(pQbuffer, ptmpuserbuffer, user_len); 146 acb->wqbuf_putIndex += user_len; 147 acb->wqbuf_putIndex %= ARCMSR_MAX_QBUFFER; 148 if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { 149 acb->acb_flags &= 150 ~ACB_F_MESSAGE_WQBUFFER_CLEARED; 151 arcmsr_write_ioctldata2iop(acb); 152 } 153 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); 154 return count; 155 } 156 } 157 158 static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, 159 struct kobject *kobj, 160 struct bin_attribute *bin, 161 char *buf, loff_t off, 162 size_t count) 163 { 164 struct device *dev = container_of(kobj,struct device,kobj); 165 struct Scsi_Host *host = class_to_shost(dev); 166 struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; 167 uint8_t *pQbuffer; 168 unsigned long flags; 169 170 if (!capable(CAP_SYS_ADMIN)) 171 return -EACCES; 172 173 arcmsr_clear_iop2drv_rqueue_buffer(acb); 174 acb->acb_flags |= 175 (ACB_F_MESSAGE_WQBUFFER_CLEARED 176 | ACB_F_MESSAGE_RQBUFFER_CLEARED 177 | ACB_F_MESSAGE_WQBUFFER_READED); 178 spin_lock_irqsave(&acb->rqbuffer_lock, flags); 179 acb->rqbuf_getIndex = 0; 180 acb->rqbuf_putIndex = 0; 181 spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); 182 spin_lock_irqsave(&acb->wqbuffer_lock, flags); 183 acb->wqbuf_getIndex = 0; 184 acb->wqbuf_putIndex = 0; 185 spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); 186 pQbuffer = acb->rqbuffer; 187 memset(pQbuffer, 0, sizeof (struct QBUFFER)); 188 pQbuffer = acb->wqbuffer; 189 memset(pQbuffer, 0, sizeof (struct QBUFFER)); 190 return 1; 191 } 192 193 static const struct bin_attribute arcmsr_sysfs_message_read_attr = { 194 .attr = { 195 .name = "mu_read", 196 .mode = S_IRUSR , 197 }, 198 .size = ARCMSR_API_DATA_BUFLEN, 199 .read = arcmsr_sysfs_iop_message_read, 200 }; 201 202 static const struct bin_attribute arcmsr_sysfs_message_write_attr = { 203 .attr = { 204 .name = "mu_write", 205 .mode = S_IWUSR, 206 }, 207 .size = ARCMSR_API_DATA_BUFLEN, 208 .write = arcmsr_sysfs_iop_message_write, 209 }; 210 211 static const struct bin_attribute arcmsr_sysfs_message_clear_attr = { 212 .attr = { 213 .name = "mu_clear", 214 .mode = S_IWUSR, 215 }, 216 .size = 1, 217 .write = arcmsr_sysfs_iop_message_clear, 218 }; 219 220 int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) 221 { 222 struct Scsi_Host *host = acb->host; 223 int error; 224 225 error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); 226 if (error) { 227 printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n"); 228 goto error_bin_file_message_read; 229 } 230 error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); 231 if (error) { 232 printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n"); 233 goto error_bin_file_message_write; 234 } 235 error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr); 236 if (error) { 237 printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n"); 238 goto error_bin_file_message_clear; 239 } 240 return 0; 241 error_bin_file_message_clear: 242 sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); 243 error_bin_file_message_write: 244 sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); 245 error_bin_file_message_read: 246 return error; 247 } 248 249 void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) 250 { 251 struct Scsi_Host *host = acb->host; 252 253 sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr); 254 sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); 255 sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); 256 } 257 258 259 static ssize_t 260 arcmsr_attr_host_driver_version(struct device *dev, 261 struct device_attribute *attr, char *buf) 262 { 263 return snprintf(buf, PAGE_SIZE, 264 "%s\n", 265 ARCMSR_DRIVER_VERSION); 266 } 267 268 static ssize_t 269 arcmsr_attr_host_driver_posted_cmd(struct device *dev, 270 struct device_attribute *attr, char *buf) 271 { 272 struct Scsi_Host *host = class_to_shost(dev); 273 struct AdapterControlBlock *acb = 274 (struct AdapterControlBlock *) host->hostdata; 275 return snprintf(buf, PAGE_SIZE, 276 "%4d\n", 277 atomic_read(&acb->ccboutstandingcount)); 278 } 279 280 static ssize_t 281 arcmsr_attr_host_driver_reset(struct device *dev, 282 struct device_attribute *attr, char *buf) 283 { 284 struct Scsi_Host *host = class_to_shost(dev); 285 struct AdapterControlBlock *acb = 286 (struct AdapterControlBlock *) host->hostdata; 287 return snprintf(buf, PAGE_SIZE, 288 "%4d\n", 289 acb->num_resets); 290 } 291 292 static ssize_t 293 arcmsr_attr_host_driver_abort(struct device *dev, 294 struct device_attribute *attr, char *buf) 295 { 296 struct Scsi_Host *host = class_to_shost(dev); 297 struct AdapterControlBlock *acb = 298 (struct AdapterControlBlock *) host->hostdata; 299 return snprintf(buf, PAGE_SIZE, 300 "%4d\n", 301 acb->num_aborts); 302 } 303 304 static ssize_t 305 arcmsr_attr_host_fw_model(struct device *dev, struct device_attribute *attr, 306 char *buf) 307 { 308 struct Scsi_Host *host = class_to_shost(dev); 309 struct AdapterControlBlock *acb = 310 (struct AdapterControlBlock *) host->hostdata; 311 return snprintf(buf, PAGE_SIZE, 312 "%s\n", 313 acb->firm_model); 314 } 315 316 static ssize_t 317 arcmsr_attr_host_fw_version(struct device *dev, 318 struct device_attribute *attr, char *buf) 319 { 320 struct Scsi_Host *host = class_to_shost(dev); 321 struct AdapterControlBlock *acb = 322 (struct AdapterControlBlock *) host->hostdata; 323 324 return snprintf(buf, PAGE_SIZE, 325 "%s\n", 326 acb->firm_version); 327 } 328 329 static ssize_t 330 arcmsr_attr_host_fw_request_len(struct device *dev, 331 struct device_attribute *attr, char *buf) 332 { 333 struct Scsi_Host *host = class_to_shost(dev); 334 struct AdapterControlBlock *acb = 335 (struct AdapterControlBlock *) host->hostdata; 336 337 return snprintf(buf, PAGE_SIZE, 338 "%4d\n", 339 acb->firm_request_len); 340 } 341 342 static ssize_t 343 arcmsr_attr_host_fw_numbers_queue(struct device *dev, 344 struct device_attribute *attr, char *buf) 345 { 346 struct Scsi_Host *host = class_to_shost(dev); 347 struct AdapterControlBlock *acb = 348 (struct AdapterControlBlock *) host->hostdata; 349 350 return snprintf(buf, PAGE_SIZE, 351 "%4d\n", 352 acb->firm_numbers_queue); 353 } 354 355 static ssize_t 356 arcmsr_attr_host_fw_sdram_size(struct device *dev, 357 struct device_attribute *attr, char *buf) 358 { 359 struct Scsi_Host *host = class_to_shost(dev); 360 struct AdapterControlBlock *acb = 361 (struct AdapterControlBlock *) host->hostdata; 362 363 return snprintf(buf, PAGE_SIZE, 364 "%4d\n", 365 acb->firm_sdram_size); 366 } 367 368 static ssize_t 369 arcmsr_attr_host_fw_hd_channels(struct device *dev, 370 struct device_attribute *attr, char *buf) 371 { 372 struct Scsi_Host *host = class_to_shost(dev); 373 struct AdapterControlBlock *acb = 374 (struct AdapterControlBlock *) host->hostdata; 375 376 return snprintf(buf, PAGE_SIZE, 377 "%4d\n", 378 acb->firm_hd_channels); 379 } 380 381 static DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL); 382 static DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL); 383 static DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL); 384 static DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL); 385 static DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL); 386 static DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL); 387 static DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL); 388 static DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL); 389 static DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL); 390 static DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL); 391 392 struct device_attribute *arcmsr_host_attrs[] = { 393 &dev_attr_host_driver_version, 394 &dev_attr_host_driver_posted_cmd, 395 &dev_attr_host_driver_reset, 396 &dev_attr_host_driver_abort, 397 &dev_attr_host_fw_model, 398 &dev_attr_host_fw_version, 399 &dev_attr_host_fw_request_len, 400 &dev_attr_host_fw_numbers_queue, 401 &dev_attr_host_fw_sdram_size, 402 &dev_attr_host_fw_hd_channels, 403 NULL, 404 }; 405