| /* |
| * Implementation of Utility functions for all SCSI device types. |
| * |
| * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. |
| * Copyright (c) 1997, 1998 Kenneth D. Merry. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions, and the following disclaimer, |
| * without modification, immediately at the beginning of the file. |
| * 2. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * |
| * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $ |
| * $Id$ |
| */ |
| |
| #include "aiclib.h" |
| |
| |
| /* |
| * Table of syncrates that don't follow the "divisible by 4" |
| * rule. This table will be expanded in future SCSI specs. |
| */ |
| static struct { |
| u_int period_factor; |
| u_int period; /* in 100ths of ns */ |
| } scsi_syncrates[] = { |
| { 0x08, 625 }, /* FAST-160 */ |
| { 0x09, 1250 }, /* FAST-80 */ |
| { 0x0a, 2500 }, /* FAST-40 40MHz */ |
| { 0x0b, 3030 }, /* FAST-40 33MHz */ |
| { 0x0c, 5000 } /* FAST-20 */ |
| }; |
| |
| /* |
| * Return the frequency in kHz corresponding to the given |
| * sync period factor. |
| */ |
| u_int |
| aic_calc_syncsrate(u_int period_factor) |
| { |
| int i; |
| int num_syncrates; |
| |
| num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); |
| /* See if the period is in the "exception" table */ |
| for (i = 0; i < num_syncrates; i++) { |
| |
| if (period_factor == scsi_syncrates[i].period_factor) { |
| /* Period in kHz */ |
| return (100000000 / scsi_syncrates[i].period); |
| } |
| } |
| |
| /* |
| * Wasn't in the table, so use the standard |
| * 4 times conversion. |
| */ |
| return (10000000 / (period_factor * 4 * 10)); |
| } |
| |
| char * |
| aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, |
| aic_option_callback_t *callback, u_long callback_arg) |
| { |
| char *tok_end; |
| char *tok_end2; |
| int i; |
| int instance; |
| int targ; |
| int done; |
| char tok_list[] = {'.', ',', '{', '}', '\0'}; |
| |
| /* All options use a ':' name/arg separator */ |
| if (*opt_arg != ':') |
| return (opt_arg); |
| opt_arg++; |
| instance = -1; |
| targ = -1; |
| done = FALSE; |
| /* |
| * Restore separator that may be in |
| * the middle of our option argument. |
| */ |
| tok_end = strchr(opt_arg, '\0'); |
| if (tok_end < end) |
| *tok_end = ','; |
| while (!done) { |
| switch (*opt_arg) { |
| case '{': |
| if (instance == -1) { |
| instance = 0; |
| } else { |
| if (depth > 1) { |
| if (targ == -1) |
| targ = 0; |
| } else { |
| printf("Malformed Option %s\n", |
| opt_name); |
| done = TRUE; |
| } |
| } |
| opt_arg++; |
| break; |
| case '}': |
| if (targ != -1) |
| targ = -1; |
| else if (instance != -1) |
| instance = -1; |
| opt_arg++; |
| break; |
| case ',': |
| case '.': |
| if (instance == -1) |
| done = TRUE; |
| else if (targ >= 0) |
| targ++; |
| else if (instance >= 0) |
| instance++; |
| opt_arg++; |
| break; |
| case '\0': |
| done = TRUE; |
| break; |
| default: |
| tok_end = end; |
| for (i = 0; tok_list[i]; i++) { |
| tok_end2 = strchr(opt_arg, tok_list[i]); |
| if ((tok_end2) && (tok_end2 < tok_end)) |
| tok_end = tok_end2; |
| } |
| callback(callback_arg, instance, targ, |
| simple_strtol(opt_arg, NULL, 0)); |
| opt_arg = tok_end; |
| break; |
| } |
| } |
| return (opt_arg); |
| } |