[SCSI] implement parameter limits in the SPI transport class

There's a basic need not to have parameters go under or over certain
values when doing domain validation. The basic ones are

max_offset, max_width and min_period

This patch makes the transport class take and enforce these three
limits. Currently they can be set by the user, although they could
obviously be read from the HBA's on-board NVRAM area during
slave_configure (if it has one).

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by James Bottomley and committed by James Bottomley 62a86129 88d7bd8c

+167 -27
+161 -27
drivers/scsi/scsi_transport_spi.c
··· 35 36 #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) 37 38 - #define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ 39 #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always 40 * on" attributes */ 41 #define SPI_HOST_ATTRS 1 ··· 219 struct scsi_target *starget = to_scsi_target(dev); 220 221 spi_period(starget) = -1; /* illegal value */ 222 spi_offset(starget) = 0; /* async */ 223 spi_width(starget) = 0; /* narrow */ 224 spi_iu(starget) = 0; /* no IU */ 225 spi_dt(starget) = 0; /* ST */ 226 spi_qas(starget) = 0; ··· 236 init_MUTEX(&spi_dv_sem(starget)); 237 238 return 0; 239 } 240 241 #define spi_transport_show_function(field, format_string) \ ··· 292 struct spi_internal *i = to_spi_internal(shost->transportt); \ 293 \ 294 val = simple_strtoul(buf, NULL, 0); \ 295 i->f->set_##field(starget, val); \ 296 return count; \ 297 } ··· 322 show_spi_transport_##field, \ 323 store_spi_transport_##field); 324 325 /* The Parallel SCSI Tranport Attributes: */ 326 - spi_transport_rd_attr(offset, "%d\n"); 327 - spi_transport_rd_attr(width, "%d\n"); 328 spi_transport_rd_attr(iu, "%d\n"); 329 spi_transport_rd_attr(dt, "%d\n"); 330 spi_transport_rd_attr(qas, "%d\n"); ··· 365 366 /* Translate the period into ns according to the current spec 367 * for SDTR/PPR messages */ 368 - static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) 369 - 370 { 371 - struct scsi_target *starget = transport_class_to_starget(cdev); 372 - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 373 - struct spi_transport_attrs *tp; 374 int len, picosec; 375 - struct spi_internal *i = to_spi_internal(shost->transportt); 376 377 - tp = (struct spi_transport_attrs *)&starget->starget_data; 378 - 379 - if (i->f->get_period) 380 - i->f->get_period(starget); 381 - 382 - if (tp->period < 0 || tp->period > 0xff) { 383 picosec = -1; 384 - } else if (tp->period <= SPI_STATIC_PPR) { 385 - picosec = ppr_to_ps[tp->period]; 386 } else { 387 - picosec = tp->period * 4000; 388 } 389 390 if (picosec == -1) { ··· 391 } 392 393 static ssize_t 394 - store_spi_transport_period(struct class_device *cdev, const char *buf, 395 - size_t count) 396 { 397 - struct scsi_target *starget = transport_class_to_starget(cdev); 398 - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 399 - struct spi_internal *i = to_spi_internal(shost->transportt); 400 int j, picosec, period = -1; 401 char *endp; 402 ··· 422 if (period > 0xff) 423 period = 0xff; 424 425 - i->f->set_period(starget, period); 426 427 return count; 428 } 429 430 static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 431 show_spi_transport_period, 432 store_spi_transport_period); 433 434 static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) 435 { ··· 760 { 761 struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); 762 struct scsi_device *sdev = sreq->sr_device; 763 int len = sdev->inquiry_len; 764 /* first set us up for narrow async */ 765 DV_SET(offset, 0); ··· 774 } 775 776 /* test width */ 777 - if (i->f->set_width && sdev->wdtr) { 778 i->f->set_width(sdev->sdev_target, 1); 779 780 if (spi_dv_device_compare_inquiry(sreq, buffer, 781 buffer + len, ··· 805 retry: 806 807 /* now set up to the maximum */ 808 - DV_SET(offset, 255); 809 - DV_SET(period, 1); 810 811 if (len == 0) { 812 SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); ··· 1013 if (i->f->show_##field) \ 1014 count++ 1015 1016 #define SETUP_HOST_ATTRIBUTE(field) \ 1017 i->private_host_attrs[count] = class_device_attr_##field; \ 1018 if (!i->f->set_##field) { \ ··· 1106 i->f = ft; 1107 1108 SETUP_ATTRIBUTE(period); 1109 SETUP_ATTRIBUTE(offset); 1110 SETUP_ATTRIBUTE(width); 1111 SETUP_ATTRIBUTE(iu); 1112 SETUP_ATTRIBUTE(dt); 1113 SETUP_ATTRIBUTE(qas);
··· 35 36 #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) 37 38 + #define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ 39 #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always 40 * on" attributes */ 41 #define SPI_HOST_ATTRS 1 ··· 219 struct scsi_target *starget = to_scsi_target(dev); 220 221 spi_period(starget) = -1; /* illegal value */ 222 + spi_min_period(starget) = 0; 223 spi_offset(starget) = 0; /* async */ 224 + spi_max_offset(starget) = 255; 225 spi_width(starget) = 0; /* narrow */ 226 + spi_max_width(starget) = 1; 227 spi_iu(starget) = 0; /* no IU */ 228 spi_dt(starget) = 0; /* ST */ 229 spi_qas(starget) = 0; ··· 233 init_MUTEX(&spi_dv_sem(starget)); 234 235 return 0; 236 + } 237 + 238 + #define spi_transport_show_simple(field, format_string) \ 239 + \ 240 + static ssize_t \ 241 + show_spi_transport_##field(struct class_device *cdev, char *buf) \ 242 + { \ 243 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 244 + struct spi_transport_attrs *tp; \ 245 + \ 246 + tp = (struct spi_transport_attrs *)&starget->starget_data; \ 247 + return snprintf(buf, 20, format_string, tp->field); \ 248 + } 249 + 250 + #define spi_transport_store_simple(field, format_string) \ 251 + \ 252 + static ssize_t \ 253 + store_spi_transport_##field(struct class_device *cdev, const char *buf, \ 254 + size_t count) \ 255 + { \ 256 + int val; \ 257 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 258 + struct spi_transport_attrs *tp; \ 259 + \ 260 + tp = (struct spi_transport_attrs *)&starget->starget_data; \ 261 + val = simple_strtoul(buf, NULL, 0); \ 262 + tp->field = val; \ 263 + return count; \ 264 } 265 266 #define spi_transport_show_function(field, format_string) \ ··· 261 struct spi_internal *i = to_spi_internal(shost->transportt); \ 262 \ 263 val = simple_strtoul(buf, NULL, 0); \ 264 + i->f->set_##field(starget, val); \ 265 + return count; \ 266 + } 267 + 268 + #define spi_transport_store_max(field, format_string) \ 269 + static ssize_t \ 270 + store_spi_transport_##field(struct class_device *cdev, const char *buf, \ 271 + size_t count) \ 272 + { \ 273 + int val; \ 274 + struct scsi_target *starget = transport_class_to_starget(cdev); \ 275 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ 276 + struct spi_internal *i = to_spi_internal(shost->transportt); \ 277 + struct spi_transport_attrs *tp \ 278 + = (struct spi_transport_attrs *)&starget->starget_data; \ 279 + \ 280 + val = simple_strtoul(buf, NULL, 0); \ 281 + if (val > tp->max_##field) \ 282 + val = tp->max_##field; \ 283 i->f->set_##field(starget, val); \ 284 return count; \ 285 } ··· 272 show_spi_transport_##field, \ 273 store_spi_transport_##field); 274 275 + #define spi_transport_simple_attr(field, format_string) \ 276 + spi_transport_show_simple(field, format_string) \ 277 + spi_transport_store_simple(field, format_string) \ 278 + static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ 279 + show_spi_transport_##field, \ 280 + store_spi_transport_##field); 281 + 282 + #define spi_transport_max_attr(field, format_string) \ 283 + spi_transport_show_function(field, format_string) \ 284 + spi_transport_store_max(field, format_string) \ 285 + spi_transport_simple_attr(max_##field, format_string) \ 286 + static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ 287 + show_spi_transport_##field, \ 288 + store_spi_transport_##field); 289 + 290 /* The Parallel SCSI Tranport Attributes: */ 291 + spi_transport_max_attr(offset, "%d\n"); 292 + spi_transport_max_attr(width, "%d\n"); 293 spi_transport_rd_attr(iu, "%d\n"); 294 spi_transport_rd_attr(dt, "%d\n"); 295 spi_transport_rd_attr(qas, "%d\n"); ··· 300 301 /* Translate the period into ns according to the current spec 302 * for SDTR/PPR messages */ 303 + static ssize_t 304 + show_spi_transport_period_helper(struct class_device *cdev, char *buf, 305 + int period) 306 { 307 int len, picosec; 308 309 + if (period < 0 || period > 0xff) { 310 picosec = -1; 311 + } else if (period <= SPI_STATIC_PPR) { 312 + picosec = ppr_to_ps[period]; 313 } else { 314 + picosec = period * 4000; 315 } 316 317 if (picosec == -1) { ··· 334 } 335 336 static ssize_t 337 + store_spi_transport_period_helper(struct class_device *cdev, const char *buf, 338 + size_t count, int *periodp) 339 { 340 int j, picosec, period = -1; 341 char *endp; 342 ··· 368 if (period > 0xff) 369 period = 0xff; 370 371 + *periodp = period; 372 373 return count; 374 + } 375 + 376 + static ssize_t 377 + show_spi_transport_period(struct class_device *cdev, char *buf) 378 + { 379 + struct scsi_target *starget = transport_class_to_starget(cdev); 380 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 381 + struct spi_internal *i = to_spi_internal(shost->transportt); 382 + struct spi_transport_attrs *tp = 383 + (struct spi_transport_attrs *)&starget->starget_data; 384 + 385 + if (i->f->get_period) 386 + i->f->get_period(starget); 387 + 388 + return show_spi_transport_period_helper(cdev, buf, tp->period); 389 + } 390 + 391 + static ssize_t 392 + store_spi_transport_period(struct class_device *cdev, const char *buf, 393 + size_t count) 394 + { 395 + struct scsi_target *starget = transport_class_to_starget(cdev); 396 + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 397 + struct spi_internal *i = to_spi_internal(shost->transportt); 398 + struct spi_transport_attrs *tp = 399 + (struct spi_transport_attrs *)&starget->starget_data; 400 + int period, retval; 401 + 402 + retval = store_spi_transport_period_helper(cdev, buf, count, &period); 403 + 404 + if (period < tp->min_period) 405 + period = tp->min_period; 406 + 407 + i->f->set_period(starget, period); 408 + 409 + return retval; 410 } 411 412 static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 413 show_spi_transport_period, 414 store_spi_transport_period); 415 + 416 + static ssize_t 417 + show_spi_transport_min_period(struct class_device *cdev, char *buf) 418 + { 419 + struct scsi_target *starget = transport_class_to_starget(cdev); 420 + struct spi_transport_attrs *tp = 421 + (struct spi_transport_attrs *)&starget->starget_data; 422 + 423 + return show_spi_transport_period_helper(cdev, buf, tp->min_period); 424 + } 425 + 426 + static ssize_t 427 + store_spi_transport_min_period(struct class_device *cdev, const char *buf, 428 + size_t count) 429 + { 430 + struct scsi_target *starget = transport_class_to_starget(cdev); 431 + struct spi_transport_attrs *tp = 432 + (struct spi_transport_attrs *)&starget->starget_data; 433 + 434 + return store_spi_transport_period_helper(cdev, buf, count, 435 + &tp->min_period); 436 + } 437 + 438 + 439 + static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 440 + show_spi_transport_min_period, 441 + store_spi_transport_min_period); 442 + 443 444 static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) 445 { ··· 642 { 643 struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); 644 struct scsi_device *sdev = sreq->sr_device; 645 + struct scsi_target *starget = sdev->sdev_target; 646 int len = sdev->inquiry_len; 647 /* first set us up for narrow async */ 648 DV_SET(offset, 0); ··· 655 } 656 657 /* test width */ 658 + if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { 659 i->f->set_width(sdev->sdev_target, 1); 660 + 661 + printk("WIDTH IS %d\n", spi_max_width(starget)); 662 663 if (spi_dv_device_compare_inquiry(sreq, buffer, 664 buffer + len, ··· 684 retry: 685 686 /* now set up to the maximum */ 687 + DV_SET(offset, spi_max_offset(starget)); 688 + DV_SET(period, spi_min_period(starget)); 689 690 if (len == 0) { 691 SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); ··· 892 if (i->f->show_##field) \ 893 count++ 894 895 + #define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ 896 + i->private_attrs[count] = class_device_attr_##field; \ 897 + if (!i->f->set_##rel_field) { \ 898 + i->private_attrs[count].attr.mode = S_IRUGO; \ 899 + i->private_attrs[count].store = NULL; \ 900 + } \ 901 + i->attrs[count] = &i->private_attrs[count]; \ 902 + if (i->f->show_##rel_field) \ 903 + count++ 904 + 905 #define SETUP_HOST_ATTRIBUTE(field) \ 906 i->private_host_attrs[count] = class_device_attr_##field; \ 907 if (!i->f->set_##field) { \ ··· 975 i->f = ft; 976 977 SETUP_ATTRIBUTE(period); 978 + SETUP_RELATED_ATTRIBUTE(min_period, period); 979 SETUP_ATTRIBUTE(offset); 980 + SETUP_RELATED_ATTRIBUTE(max_offset, offset); 981 SETUP_ATTRIBUTE(width); 982 + SETUP_RELATED_ATTRIBUTE(max_width, width); 983 SETUP_ATTRIBUTE(iu); 984 SETUP_ATTRIBUTE(dt); 985 SETUP_ATTRIBUTE(qas);
+6
include/scsi/scsi_transport_spi.h
··· 27 28 struct spi_transport_attrs { 29 int period; /* value in the PPR/SDTR command */ 30 int offset; 31 unsigned int width:1; /* 0 - narrow, 1 - wide */ 32 unsigned int iu:1; /* Information Units enabled */ 33 unsigned int dt:1; /* DT clocking enabled */ 34 unsigned int qas:1; /* Quick Arbitration and Selection enabled */ ··· 66 67 /* accessor functions */ 68 #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) 69 #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) 70 #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) 71 #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) 72 #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) 73 #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)
··· 27 28 struct spi_transport_attrs { 29 int period; /* value in the PPR/SDTR command */ 30 + int min_period; 31 int offset; 32 + int max_offset; 33 unsigned int width:1; /* 0 - narrow, 1 - wide */ 34 + unsigned int max_width:1; 35 unsigned int iu:1; /* Information Units enabled */ 36 unsigned int dt:1; /* DT clocking enabled */ 37 unsigned int qas:1; /* Quick Arbitration and Selection enabled */ ··· 63 64 /* accessor functions */ 65 #define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period) 66 + #define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period) 67 #define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset) 68 + #define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset) 69 #define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width) 70 + #define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width) 71 #define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu) 72 #define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt) 73 #define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)