diff options
| -rw-r--r-- | drivers/scsi/scsi_transport_spi.c | 188 | ||||
| -rw-r--r-- | include/scsi/scsi_transport_spi.h | 6 |
2 files changed, 167 insertions, 27 deletions
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 28966d05435c..67c6cc40ce16 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | 35 | ||
| 36 | #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) | 36 | #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) |
| 37 | 37 | ||
| 38 | #define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ | 38 | #define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ |
| 39 | #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always | 39 | #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always |
| 40 | * on" attributes */ | 40 | * on" attributes */ |
| 41 | #define SPI_HOST_ATTRS 1 | 41 | #define SPI_HOST_ATTRS 1 |
| @@ -219,8 +219,11 @@ static int spi_setup_transport_attrs(struct device *dev) | |||
| 219 | struct scsi_target *starget = to_scsi_target(dev); | 219 | struct scsi_target *starget = to_scsi_target(dev); |
| 220 | 220 | ||
| 221 | spi_period(starget) = -1; /* illegal value */ | 221 | spi_period(starget) = -1; /* illegal value */ |
| 222 | spi_min_period(starget) = 0; | ||
| 222 | spi_offset(starget) = 0; /* async */ | 223 | spi_offset(starget) = 0; /* async */ |
| 224 | spi_max_offset(starget) = 255; | ||
| 223 | spi_width(starget) = 0; /* narrow */ | 225 | spi_width(starget) = 0; /* narrow */ |
| 226 | spi_max_width(starget) = 1; | ||
| 224 | spi_iu(starget) = 0; /* no IU */ | 227 | spi_iu(starget) = 0; /* no IU */ |
| 225 | spi_dt(starget) = 0; /* ST */ | 228 | spi_dt(starget) = 0; /* ST */ |
| 226 | spi_qas(starget) = 0; | 229 | spi_qas(starget) = 0; |
| @@ -235,6 +238,34 @@ static int spi_setup_transport_attrs(struct device *dev) | |||
| 235 | return 0; | 238 | return 0; |
| 236 | } | 239 | } |
| 237 | 240 | ||
| 241 | #define spi_transport_show_simple(field, format_string) \ | ||
| 242 | \ | ||
| 243 | static ssize_t \ | ||
| 244 | show_spi_transport_##field(struct class_device *cdev, char *buf) \ | ||
| 245 | { \ | ||
| 246 | struct scsi_target *starget = transport_class_to_starget(cdev); \ | ||
| 247 | struct spi_transport_attrs *tp; \ | ||
| 248 | \ | ||
| 249 | tp = (struct spi_transport_attrs *)&starget->starget_data; \ | ||
| 250 | return snprintf(buf, 20, format_string, tp->field); \ | ||
| 251 | } | ||
| 252 | |||
| 253 | #define spi_transport_store_simple(field, format_string) \ | ||
| 254 | \ | ||
| 255 | static ssize_t \ | ||
| 256 | store_spi_transport_##field(struct class_device *cdev, const char *buf, \ | ||
| 257 | size_t count) \ | ||
| 258 | { \ | ||
| 259 | int val; \ | ||
| 260 | struct scsi_target *starget = transport_class_to_starget(cdev); \ | ||
| 261 | struct spi_transport_attrs *tp; \ | ||
| 262 | \ | ||
| 263 | tp = (struct spi_transport_attrs *)&starget->starget_data; \ | ||
| 264 | val = simple_strtoul(buf, NULL, 0); \ | ||
| 265 | tp->field = val; \ | ||
| 266 | return count; \ | ||
| 267 | } | ||
| 268 | |||
| 238 | #define spi_transport_show_function(field, format_string) \ | 269 | #define spi_transport_show_function(field, format_string) \ |
| 239 | \ | 270 | \ |
| 240 | static ssize_t \ | 271 | static ssize_t \ |
| @@ -261,6 +292,25 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ | |||
| 261 | struct spi_internal *i = to_spi_internal(shost->transportt); \ | 292 | struct spi_internal *i = to_spi_internal(shost->transportt); \ |
| 262 | \ | 293 | \ |
| 263 | val = simple_strtoul(buf, NULL, 0); \ | 294 | val = simple_strtoul(buf, NULL, 0); \ |
| 295 | i->f->set_##field(starget, val); \ | ||
| 296 | return count; \ | ||
| 297 | } | ||
| 298 | |||
| 299 | #define spi_transport_store_max(field, format_string) \ | ||
| 300 | static ssize_t \ | ||
| 301 | store_spi_transport_##field(struct class_device *cdev, const char *buf, \ | ||
| 302 | size_t count) \ | ||
| 303 | { \ | ||
| 304 | int val; \ | ||
| 305 | struct scsi_target *starget = transport_class_to_starget(cdev); \ | ||
| 306 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ | ||
| 307 | struct spi_internal *i = to_spi_internal(shost->transportt); \ | ||
| 308 | struct spi_transport_attrs *tp \ | ||
| 309 | = (struct spi_transport_attrs *)&starget->starget_data; \ | ||
| 310 | \ | ||
| 311 | val = simple_strtoul(buf, NULL, 0); \ | ||
| 312 | if (val > tp->max_##field) \ | ||
| 313 | val = tp->max_##field; \ | ||
| 264 | i->f->set_##field(starget, val); \ | 314 | i->f->set_##field(starget, val); \ |
| 265 | return count; \ | 315 | return count; \ |
| 266 | } | 316 | } |
| @@ -272,9 +322,24 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ | |||
| 272 | show_spi_transport_##field, \ | 322 | show_spi_transport_##field, \ |
| 273 | store_spi_transport_##field); | 323 | store_spi_transport_##field); |
| 274 | 324 | ||
| 325 | #define spi_transport_simple_attr(field, format_string) \ | ||
| 326 | spi_transport_show_simple(field, format_string) \ | ||
| 327 | spi_transport_store_simple(field, format_string) \ | ||
| 328 | static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ | ||
| 329 | show_spi_transport_##field, \ | ||
| 330 | store_spi_transport_##field); | ||
| 331 | |||
| 332 | #define spi_transport_max_attr(field, format_string) \ | ||
| 333 | spi_transport_show_function(field, format_string) \ | ||
| 334 | spi_transport_store_max(field, format_string) \ | ||
| 335 | spi_transport_simple_attr(max_##field, format_string) \ | ||
| 336 | static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ | ||
| 337 | show_spi_transport_##field, \ | ||
| 338 | store_spi_transport_##field); | ||
| 339 | |||
| 275 | /* The Parallel SCSI Tranport Attributes: */ | 340 | /* The Parallel SCSI Tranport Attributes: */ |
| 276 | spi_transport_rd_attr(offset, "%d\n"); | 341 | spi_transport_max_attr(offset, "%d\n"); |
| 277 | spi_transport_rd_attr(width, "%d\n"); | 342 | spi_transport_max_attr(width, "%d\n"); |
| 278 | spi_transport_rd_attr(iu, "%d\n"); | 343 | spi_transport_rd_attr(iu, "%d\n"); |
| 279 | spi_transport_rd_attr(dt, "%d\n"); | 344 | spi_transport_rd_attr(dt, "%d\n"); |
| 280 | spi_transport_rd_attr(qas, "%d\n"); | 345 | spi_transport_rd_attr(qas, "%d\n"); |
| @@ -300,26 +365,18 @@ static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); | |||
| 300 | 365 | ||
| 301 | /* Translate the period into ns according to the current spec | 366 | /* Translate the period into ns according to the current spec |
| 302 | * for SDTR/PPR messages */ | 367 | * for SDTR/PPR messages */ |
| 303 | static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) | 368 | static ssize_t |
| 304 | 369 | show_spi_transport_period_helper(struct class_device *cdev, char *buf, | |
| 370 | int period) | ||
| 305 | { | 371 | { |
| 306 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 307 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
| 308 | struct spi_transport_attrs *tp; | ||
| 309 | int len, picosec; | 372 | int len, picosec; |
| 310 | struct spi_internal *i = to_spi_internal(shost->transportt); | ||
| 311 | |||
| 312 | tp = (struct spi_transport_attrs *)&starget->starget_data; | ||
| 313 | |||
| 314 | if (i->f->get_period) | ||
| 315 | i->f->get_period(starget); | ||
| 316 | 373 | ||
| 317 | if (tp->period < 0 || tp->period > 0xff) { | 374 | if (period < 0 || period > 0xff) { |
| 318 | picosec = -1; | 375 | picosec = -1; |
| 319 | } else if (tp->period <= SPI_STATIC_PPR) { | 376 | } else if (period <= SPI_STATIC_PPR) { |
| 320 | picosec = ppr_to_ps[tp->period]; | 377 | picosec = ppr_to_ps[period]; |
| 321 | } else { | 378 | } else { |
| 322 | picosec = tp->period * 4000; | 379 | picosec = period * 4000; |
| 323 | } | 380 | } |
| 324 | 381 | ||
| 325 | if (picosec == -1) { | 382 | if (picosec == -1) { |
| @@ -334,12 +391,9 @@ static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) | |||
| 334 | } | 391 | } |
| 335 | 392 | ||
| 336 | static ssize_t | 393 | static ssize_t |
| 337 | store_spi_transport_period(struct class_device *cdev, const char *buf, | 394 | store_spi_transport_period_helper(struct class_device *cdev, const char *buf, |
| 338 | size_t count) | 395 | size_t count, int *periodp) |
| 339 | { | 396 | { |
| 340 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 341 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
| 342 | struct spi_internal *i = to_spi_internal(shost->transportt); | ||
| 343 | int j, picosec, period = -1; | 397 | int j, picosec, period = -1; |
| 344 | char *endp; | 398 | char *endp; |
| 345 | 399 | ||
| @@ -368,15 +422,79 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, | |||
| 368 | if (period > 0xff) | 422 | if (period > 0xff) |
| 369 | period = 0xff; | 423 | period = 0xff; |
| 370 | 424 | ||
| 371 | i->f->set_period(starget, period); | 425 | *periodp = period; |
| 372 | 426 | ||
| 373 | return count; | 427 | return count; |
| 374 | } | 428 | } |
| 375 | 429 | ||
| 430 | static ssize_t | ||
| 431 | show_spi_transport_period(struct class_device *cdev, char *buf) | ||
| 432 | { | ||
| 433 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 434 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
| 435 | struct spi_internal *i = to_spi_internal(shost->transportt); | ||
| 436 | struct spi_transport_attrs *tp = | ||
| 437 | (struct spi_transport_attrs *)&starget->starget_data; | ||
| 438 | |||
| 439 | if (i->f->get_period) | ||
| 440 | i->f->get_period(starget); | ||
| 441 | |||
| 442 | return show_spi_transport_period_helper(cdev, buf, tp->period); | ||
| 443 | } | ||
| 444 | |||
| 445 | static ssize_t | ||
| 446 | store_spi_transport_period(struct class_device *cdev, const char *buf, | ||
| 447 | size_t count) | ||
| 448 | { | ||
| 449 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 450 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
| 451 | struct spi_internal *i = to_spi_internal(shost->transportt); | ||
| 452 | struct spi_transport_attrs *tp = | ||
| 453 | (struct spi_transport_attrs *)&starget->starget_data; | ||
| 454 | int period, retval; | ||
| 455 | |||
| 456 | retval = store_spi_transport_period_helper(cdev, buf, count, &period); | ||
| 457 | |||
| 458 | if (period < tp->min_period) | ||
| 459 | period = tp->min_period; | ||
| 460 | |||
| 461 | i->f->set_period(starget, period); | ||
| 462 | |||
| 463 | return retval; | ||
| 464 | } | ||
| 465 | |||
| 376 | static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, | 466 | static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, |
| 377 | show_spi_transport_period, | 467 | show_spi_transport_period, |
| 378 | store_spi_transport_period); | 468 | store_spi_transport_period); |
| 379 | 469 | ||
| 470 | static ssize_t | ||
| 471 | show_spi_transport_min_period(struct class_device *cdev, char *buf) | ||
| 472 | { | ||
| 473 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 474 | struct spi_transport_attrs *tp = | ||
| 475 | (struct spi_transport_attrs *)&starget->starget_data; | ||
| 476 | |||
| 477 | return show_spi_transport_period_helper(cdev, buf, tp->min_period); | ||
| 478 | } | ||
| 479 | |||
| 480 | static ssize_t | ||
| 481 | store_spi_transport_min_period(struct class_device *cdev, const char *buf, | ||
| 482 | size_t count) | ||
| 483 | { | ||
| 484 | struct scsi_target *starget = transport_class_to_starget(cdev); | ||
| 485 | struct spi_transport_attrs *tp = | ||
| 486 | (struct spi_transport_attrs *)&starget->starget_data; | ||
| 487 | |||
| 488 | return store_spi_transport_period_helper(cdev, buf, count, | ||
| 489 | &tp->min_period); | ||
| 490 | } | ||
| 491 | |||
| 492 | |||
| 493 | static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, | ||
| 494 | show_spi_transport_min_period, | ||
| 495 | store_spi_transport_min_period); | ||
| 496 | |||
| 497 | |||
| 380 | static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) | 498 | static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) |
| 381 | { | 499 | { |
| 382 | struct Scsi_Host *shost = transport_class_to_shost(cdev); | 500 | struct Scsi_Host *shost = transport_class_to_shost(cdev); |
| @@ -642,6 +760,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
| 642 | { | 760 | { |
| 643 | struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); | 761 | struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); |
| 644 | struct scsi_device *sdev = sreq->sr_device; | 762 | struct scsi_device *sdev = sreq->sr_device; |
| 763 | struct scsi_target *starget = sdev->sdev_target; | ||
| 645 | int len = sdev->inquiry_len; | 764 | int len = sdev->inquiry_len; |
| 646 | /* first set us up for narrow async */ | 765 | /* first set us up for narrow async */ |
| 647 | DV_SET(offset, 0); | 766 | DV_SET(offset, 0); |
| @@ -655,9 +774,11 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
| 655 | } | 774 | } |
| 656 | 775 | ||
| 657 | /* test width */ | 776 | /* test width */ |
| 658 | if (i->f->set_width && sdev->wdtr) { | 777 | if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { |
| 659 | i->f->set_width(sdev->sdev_target, 1); | 778 | i->f->set_width(sdev->sdev_target, 1); |
| 660 | 779 | ||
| 780 | printk("WIDTH IS %d\n", spi_max_width(starget)); | ||
| 781 | |||
| 661 | if (spi_dv_device_compare_inquiry(sreq, buffer, | 782 | if (spi_dv_device_compare_inquiry(sreq, buffer, |
| 662 | buffer + len, | 783 | buffer + len, |
| 663 | DV_LOOPS) | 784 | DV_LOOPS) |
| @@ -684,8 +805,8 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
| 684 | retry: | 805 | retry: |
| 685 | 806 | ||
| 686 | /* now set up to the maximum */ | 807 | /* now set up to the maximum */ |
| 687 | DV_SET(offset, 255); | 808 | DV_SET(offset, spi_max_offset(starget)); |
| 688 | DV_SET(period, 1); | 809 | DV_SET(period, spi_min_period(starget)); |
| 689 | 810 | ||
| 690 | if (len == 0) { | 811 | if (len == 0) { |
| 691 | SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); | 812 | SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); |
| @@ -892,6 +1013,16 @@ EXPORT_SYMBOL(spi_display_xfer_agreement); | |||
| 892 | if (i->f->show_##field) \ | 1013 | if (i->f->show_##field) \ |
| 893 | count++ | 1014 | count++ |
| 894 | 1015 | ||
| 1016 | #define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ | ||
| 1017 | i->private_attrs[count] = class_device_attr_##field; \ | ||
| 1018 | if (!i->f->set_##rel_field) { \ | ||
| 1019 | i->private_attrs[count].attr.mode = S_IRUGO; \ | ||
| 1020 | i->private_attrs[count].store = NULL; \ | ||
| 1021 | } \ | ||
| 1022 | i->attrs[count] = &i->private_attrs[count]; \ | ||
| 1023 | if (i->f->show_##rel_field) \ | ||
| 1024 | count++ | ||
| 1025 | |||
| 895 | #define SETUP_HOST_ATTRIBUTE(field) \ | 1026 | #define SETUP_HOST_ATTRIBUTE(field) \ |
| 896 | i->private_host_attrs[count] = class_device_attr_##field; \ | 1027 | i->private_host_attrs[count] = class_device_attr_##field; \ |
| 897 | if (!i->f->set_##field) { \ | 1028 | if (!i->f->set_##field) { \ |
| @@ -975,8 +1106,11 @@ spi_attach_transport(struct spi_function_template *ft) | |||
| 975 | i->f = ft; | 1106 | i->f = ft; |
| 976 | 1107 | ||
| 977 | SETUP_ATTRIBUTE(period); | 1108 | SETUP_ATTRIBUTE(period); |
| 1109 | SETUP_RELATED_ATTRIBUTE(min_period, period); | ||
| 978 | SETUP_ATTRIBUTE(offset); | 1110 | SETUP_ATTRIBUTE(offset); |
| 1111 | SETUP_RELATED_ATTRIBUTE(max_offset, offset); | ||
| 979 | SETUP_ATTRIBUTE(width); | 1112 | SETUP_ATTRIBUTE(width); |
| 1113 | SETUP_RELATED_ATTRIBUTE(max_width, width); | ||
| 980 | SETUP_ATTRIBUTE(iu); | 1114 | SETUP_ATTRIBUTE(iu); |
| 981 | SETUP_ATTRIBUTE(dt); | 1115 | SETUP_ATTRIBUTE(dt); |
| 982 | SETUP_ATTRIBUTE(qas); | 1116 | SETUP_ATTRIBUTE(qas); |
diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h index 6dcf497bf46d..a30d6cd4c0e8 100644 --- a/include/scsi/scsi_transport_spi.h +++ b/include/scsi/scsi_transport_spi.h | |||
| @@ -27,8 +27,11 @@ struct scsi_transport_template; | |||
| 27 | 27 | ||
| 28 | struct spi_transport_attrs { | 28 | struct spi_transport_attrs { |
| 29 | int period; /* value in the PPR/SDTR command */ | 29 | int period; /* value in the PPR/SDTR command */ |
| 30 | int min_period; | ||
| 30 | int offset; | 31 | int offset; |
| 32 | int max_offset; | ||
| 31 | unsigned int width:1; /* 0 - narrow, 1 - wide */ | 33 | unsigned int width:1; /* 0 - narrow, 1 - wide */ |
| 34 | unsigned int max_width:1; | ||
| 32 | unsigned int iu:1; /* Information Units enabled */ | 35 | unsigned int iu:1; /* Information Units enabled */ |
| 33 | unsigned int dt:1; /* DT clocking enabled */ | 36 | unsigned int dt:1; /* DT clocking enabled */ |
| 34 | unsigned int qas:1; /* Quick Arbitration and Selection enabled */ | 37 | unsigned int qas:1; /* Quick Arbitration and Selection enabled */ |
| @@ -63,8 +66,11 @@ struct spi_host_attrs { | |||
| 63 | 66 | ||
| 64 | /* accessor functions */ | 67 | /* accessor functions */ |
| 65 | #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) | 68 | #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) |
| 69 | #define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period) | ||
| 66 | #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) | 70 | #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) |
| 71 | #define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset) | ||
| 67 | #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) | 72 | #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) |
| 73 | #define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width) | ||
| 68 | #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) | 74 | #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) |
| 69 | #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) | 75 | #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) |
| 70 | #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas) | 76 | #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas) |
