2
* Copyright (c) 2000-2001 Adaptec Inc.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions, and the following disclaimer,
10
* without modification.
11
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
12
* substantially similar to the "NO WARRANTY" disclaimer below
13
* ("Disclaimer") and any redistribution must be conditioned upon
14
* including a substantially similar Disclaimer requirement for further
15
* binary redistribution.
16
* 3. Neither the names of the above-listed copyright holders nor the names
17
* of any contributors may be used to endorse or promote products derived
18
* from this software without specific prior written permission.
20
* Alternatively, this software may be distributed under the terms of the
21
* GNU General Public License ("GPL") version 2 as published by the Free
22
* Software Foundation.
25
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
28
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
* POSSIBILITY OF SUCH DAMAGES.
37
* String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
40
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#19 $
42
#include "aic7xxx_osm.h"
43
#include "aic7xxx_inline.h"
44
#include "aic7xxx_93cx6.h"
46
static void copy_mem_info(struct info_str *info, char *data, int len);
47
static int copy_info(struct info_str *info, char *fmt, ...);
48
static u_int scsi_calc_syncsrate(u_int period_factor);
49
static void ahc_dump_target_state(struct ahc_softc *ahc,
50
struct info_str *info,
51
u_int our_id, char channel,
52
u_int target_id, u_int target_offset);
53
static void ahc_dump_device_state(struct info_str *info,
54
struct ahc_linux_device *dev);
55
static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
56
char *buffer, int length);
59
copy_mem_info(struct info_str *info, char *data, int len)
61
if (info->pos + len > info->offset + info->length)
62
len = info->offset + info->length - info->pos;
64
if (info->pos + len < info->offset) {
69
if (info->pos < info->offset) {
72
partial = info->offset - info->pos;
79
memcpy(info->buffer, data, len);
86
copy_info(struct info_str *info, char *fmt, ...)
93
len = vsprintf(buf, fmt, args);
96
copy_mem_info(info, buf, len);
101
* Table of syncrates that don't follow the "divisible by 4"
102
* rule. This table will be expanded in future SCSI specs.
106
u_int period; /* in 10ths of ns */
107
} scsi_syncrates[] = {
108
{ 0x09, 125 }, /* FAST-80 */
109
{ 0x0a, 250 }, /* FAST-40 40MHz */
110
{ 0x0b, 303 }, /* FAST-40 33MHz */
111
{ 0x0c, 500 } /* FAST-20 */
115
* Return the frequency in kHz corresponding to the given
116
* sync period factor.
119
scsi_calc_syncsrate(u_int period_factor)
124
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
125
/* See if the period is in the "exception" table */
126
for (i = 0; i < num_syncrates; i++) {
128
if (period_factor == scsi_syncrates[i].period_factor) {
130
return (10000000 / scsi_syncrates[i].period);
135
* Wasn't in the table, so use the standard
136
* 4 times conversion.
138
return (10000000 / (period_factor * 4 * 10));
142
ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
150
if (tinfo->offset != 0) {
151
freq = scsi_calc_syncsrate(tinfo->period);
154
speed *= (0x01 << tinfo->width);
157
copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
159
copy_info(info, "%dKB/s transfers", speed);
162
copy_info(info, " (%d.%03dMHz%s, offset %d",
163
freq / 1000, freq % 1000,
164
(tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
165
? " DT" : "", tinfo->offset);
168
if (tinfo->width > 0) {
170
copy_info(info, ", ");
172
copy_info(info, " (");
174
copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
175
} else if (freq != 0) {
176
copy_info(info, ")");
178
copy_info(info, "\n");
182
ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
183
u_int our_id, char channel, u_int target_id,
186
struct ahc_linux_target *targ;
187
struct ahc_initiator_tinfo *tinfo;
188
struct ahc_tmode_tstate *tstate;
191
tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
193
copy_info(info, "Channel %c Target %d Negotiation Settings\n",
195
copy_info(info, "\tUser: ");
196
ahc_format_transinfo(info, &tinfo->user);
197
targ = ahc->platform_data->targets[target_offset];
201
copy_info(info, "\tGoal: ");
202
ahc_format_transinfo(info, &tinfo->goal);
203
copy_info(info, "\tCurr: ");
204
ahc_format_transinfo(info, &tinfo->curr);
206
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
207
struct ahc_linux_device *dev;
209
dev = targ->devices[lun];
214
ahc_dump_device_state(info, dev);
219
ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
221
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
222
dev->target->channel + 'A', dev->target->target, dev->lun);
224
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
225
copy_info(info, "\t\tCommands Active %d\n", dev->active);
226
copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
227
copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
228
copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
232
ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
234
struct seeprom_descriptor sd;
240
/* Default to failure. */
243
paused = ahc_is_paused(ahc);
247
if (length != sizeof(struct seeprom_config)) {
248
printf("ahc_proc_write_seeprom: incorrect buffer size\n");
252
have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
253
if (have_seeprom == 0) {
254
printf("ahc_proc_write_seeprom: cksum verification failed\n");
259
if ((ahc->chip & AHC_VL) != 0) {
260
sd.sd_control_offset = SEECTL_2840;
261
sd.sd_status_offset = STATUS_2840;
262
sd.sd_dataout_offset = STATUS_2840;
265
sd.sd_RDY = EEPROM_TF;
272
sd.sd_control_offset = SEECTL;
273
sd.sd_status_offset = SEECTL;
274
sd.sd_dataout_offset = SEECTL;
275
if (ahc->flags & AHC_LARGE_SEEPROM)
285
have_seeprom = ahc_acquire_seeprom(ahc, &sd);
289
printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
294
if (ahc->seep_config == NULL) {
295
ahc->seep_config = malloc(sizeof(*ahc->seep_config),
297
if (ahc->seep_config == NULL) {
298
printf("aic7xxx: Unable to allocate serial "
299
"eeprom buffer. Write failing\n");
303
printf("aic7xxx: Writing Serial EEPROM\n");
304
start_addr = 32 * (ahc->channel - 'A');
305
ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
306
sizeof(struct seeprom_config)/2);
307
ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config,
308
start_addr, sizeof(struct seeprom_config)/2);
309
if ((ahc->chip & AHC_VL) == 0)
310
ahc_release_seeprom(&sd);
322
* Return information to handle /proc support for the driver.
325
ahc_linux_proc_info(char *buffer, char **start, off_t offset,
326
int length, int hostno, int inout)
328
struct ahc_softc *ahc;
329
struct info_str info;
338
TAILQ_FOREACH(ahc, &ahc_tailq, links) {
339
if (ahc->platform_data->host->host_no == hostno)
346
/* Has data been written to the file? */
348
retval = ahc_proc_write_seeprom(ahc, buffer, length);
355
info.buffer = buffer;
356
info.length = length;
357
info.offset = offset;
360
copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
361
AIC7XXX_DRIVER_VERSION);
362
ahc_controller_info(ahc, ahc_info);
363
copy_info(&info, "%s\n\n", ahc_info);
365
if (ahc->seep_config == NULL)
366
copy_info(&info, "No Serial EEPROM\n");
368
copy_info(&info, "Serial EEPROM:\n");
369
for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
370
if (((i % 8) == 0) && (i != 0)) {
371
copy_info(&info, "\n");
373
copy_info(&info, "0x%.4x ",
374
((uint16_t*)ahc->seep_config)[i]);
376
copy_info(&info, "\n");
378
copy_info(&info, "\n");
381
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
384
for (i = 0; i <= max_targ; i++) {
390
our_id = ahc->our_id;
392
if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
394
our_id = ahc->our_id_b;
398
ahc_dump_target_state(ahc, &info, our_id,
399
channel, target_id, i);
401
retval = info.pos > info.offset ? info.pos - info.offset : 0;