0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include "aic79xx_osm.h"
0043 #include "aic79xx_inline.h"
0044
0045 static void ahd_dump_target_state(struct ahd_softc *ahd,
0046 struct seq_file *m,
0047 u_int our_id, char channel,
0048 u_int target_id);
0049 static void ahd_dump_device_state(struct seq_file *m,
0050 struct scsi_device *sdev);
0051
0052
0053
0054
0055
0056 static const struct {
0057 u_int period_factor;
0058 u_int period;
0059 } scsi_syncrates[] = {
0060 { 0x08, 625 },
0061 { 0x09, 1250 },
0062 { 0x0a, 2500 },
0063 { 0x0b, 3030 },
0064 { 0x0c, 5000 }
0065 };
0066
0067
0068
0069
0070
0071 static u_int
0072 ahd_calc_syncsrate(u_int period_factor)
0073 {
0074 int i;
0075
0076
0077 for (i = 0; i < ARRAY_SIZE(scsi_syncrates); i++) {
0078
0079 if (period_factor == scsi_syncrates[i].period_factor) {
0080
0081 return (100000000 / scsi_syncrates[i].period);
0082 }
0083 }
0084
0085
0086
0087
0088
0089 return (10000000 / (period_factor * 4 * 10));
0090 }
0091
0092 static void
0093 ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo)
0094 {
0095 u_int speed;
0096 u_int freq;
0097 u_int mb;
0098
0099 if (tinfo->period == AHD_PERIOD_UNKNOWN) {
0100 seq_puts(m, "Renegotiation Pending\n");
0101 return;
0102 }
0103 speed = 3300;
0104 freq = 0;
0105 if (tinfo->offset != 0) {
0106 freq = ahd_calc_syncsrate(tinfo->period);
0107 speed = freq;
0108 }
0109 speed *= (0x01 << tinfo->width);
0110 mb = speed / 1000;
0111 if (mb > 0)
0112 seq_printf(m, "%d.%03dMB/s transfers", mb, speed % 1000);
0113 else
0114 seq_printf(m, "%dKB/s transfers", speed);
0115
0116 if (freq != 0) {
0117 int printed_options;
0118
0119 printed_options = 0;
0120 seq_printf(m, " (%d.%03dMHz", freq / 1000, freq % 1000);
0121 if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
0122 seq_puts(m, " RDSTRM");
0123 printed_options++;
0124 }
0125 if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
0126 seq_puts(m, printed_options ? "|DT" : " DT");
0127 printed_options++;
0128 }
0129 if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
0130 seq_puts(m, printed_options ? "|IU" : " IU");
0131 printed_options++;
0132 }
0133 if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) {
0134 seq_puts(m, printed_options ? "|RTI" : " RTI");
0135 printed_options++;
0136 }
0137 if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
0138 seq_puts(m, printed_options ? "|QAS" : " QAS");
0139 printed_options++;
0140 }
0141 }
0142
0143 if (tinfo->width > 0) {
0144 if (freq != 0) {
0145 seq_puts(m, ", ");
0146 } else {
0147 seq_puts(m, " (");
0148 }
0149 seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width));
0150 } else if (freq != 0) {
0151 seq_putc(m, ')');
0152 }
0153 seq_putc(m, '\n');
0154 }
0155
0156 static void
0157 ahd_dump_target_state(struct ahd_softc *ahd, struct seq_file *m,
0158 u_int our_id, char channel, u_int target_id)
0159 {
0160 struct scsi_target *starget;
0161 struct ahd_initiator_tinfo *tinfo;
0162 struct ahd_tmode_tstate *tstate;
0163 int lun;
0164
0165 tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
0166 target_id, &tstate);
0167 seq_printf(m, "Target %d Negotiation Settings\n", target_id);
0168 seq_puts(m, "\tUser: ");
0169 ahd_format_transinfo(m, &tinfo->user);
0170 starget = ahd->platform_data->starget[target_id];
0171 if (starget == NULL)
0172 return;
0173
0174 seq_puts(m, "\tGoal: ");
0175 ahd_format_transinfo(m, &tinfo->goal);
0176 seq_puts(m, "\tCurr: ");
0177 ahd_format_transinfo(m, &tinfo->curr);
0178
0179 for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
0180 struct scsi_device *dev;
0181
0182 dev = scsi_device_lookup_by_target(starget, lun);
0183
0184 if (dev == NULL)
0185 continue;
0186
0187 ahd_dump_device_state(m, dev);
0188 }
0189 }
0190
0191 static void
0192 ahd_dump_device_state(struct seq_file *m, struct scsi_device *sdev)
0193 {
0194 struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
0195
0196 seq_printf(m, "\tChannel %c Target %d Lun %d Settings\n",
0197 sdev->sdev_target->channel + 'A',
0198 sdev->sdev_target->id, (u8)sdev->lun);
0199
0200 seq_printf(m, "\t\tCommands Queued %ld\n", dev->commands_issued);
0201 seq_printf(m, "\t\tCommands Active %d\n", dev->active);
0202 seq_printf(m, "\t\tCommand Openings %d\n", dev->openings);
0203 seq_printf(m, "\t\tMax Tagged Openings %d\n", dev->maxtags);
0204 seq_printf(m, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
0205 }
0206
0207 int
0208 ahd_proc_write_seeprom(struct Scsi_Host *shost, char *buffer, int length)
0209 {
0210 struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
0211 ahd_mode_state saved_modes;
0212 int have_seeprom;
0213 u_long s;
0214 int paused;
0215 int written;
0216
0217
0218 written = -EINVAL;
0219 ahd_lock(ahd, &s);
0220 paused = ahd_is_paused(ahd);
0221 if (!paused)
0222 ahd_pause(ahd);
0223
0224 saved_modes = ahd_save_modes(ahd);
0225 ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
0226 if (length != sizeof(struct seeprom_config)) {
0227 printk("ahd_proc_write_seeprom: incorrect buffer size\n");
0228 goto done;
0229 }
0230
0231 have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
0232 if (have_seeprom == 0) {
0233 printk("ahd_proc_write_seeprom: cksum verification failed\n");
0234 goto done;
0235 }
0236
0237 have_seeprom = ahd_acquire_seeprom(ahd);
0238 if (!have_seeprom) {
0239 printk("ahd_proc_write_seeprom: No Serial EEPROM\n");
0240 goto done;
0241 } else {
0242 u_int start_addr;
0243
0244 if (ahd->seep_config == NULL) {
0245 ahd->seep_config = kmalloc(sizeof(*ahd->seep_config),
0246 GFP_ATOMIC);
0247 if (ahd->seep_config == NULL) {
0248 printk("aic79xx: Unable to allocate serial "
0249 "eeprom buffer. Write failing\n");
0250 goto done;
0251 }
0252 }
0253 printk("aic79xx: Writing Serial EEPROM\n");
0254 start_addr = 32 * (ahd->channel - 'A');
0255 ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
0256 sizeof(struct seeprom_config)/2);
0257 ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config,
0258 start_addr, sizeof(struct seeprom_config)/2,
0259 FALSE);
0260 ahd_release_seeprom(ahd);
0261 written = length;
0262 }
0263
0264 done:
0265 ahd_restore_modes(ahd, saved_modes);
0266 if (!paused)
0267 ahd_unpause(ahd);
0268 ahd_unlock(ahd, &s);
0269 return (written);
0270 }
0271
0272
0273
0274 int
0275 ahd_linux_show_info(struct seq_file *m, struct Scsi_Host *shost)
0276 {
0277 struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata;
0278 char ahd_info[256];
0279 u_int max_targ;
0280 u_int i;
0281
0282 seq_printf(m, "Adaptec AIC79xx driver version: %s\n",
0283 AIC79XX_DRIVER_VERSION);
0284 seq_printf(m, "%s\n", ahd->description);
0285 ahd_controller_info(ahd, ahd_info);
0286 seq_printf(m, "%s\n", ahd_info);
0287 seq_printf(m, "Allocated SCBs: %d, SG List Length: %d\n\n",
0288 ahd->scb_data.numscbs, AHD_NSEG);
0289
0290 max_targ = 16;
0291
0292 if (ahd->seep_config == NULL)
0293 seq_puts(m, "No Serial EEPROM\n");
0294 else {
0295 seq_puts(m, "Serial EEPROM:\n");
0296 for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) {
0297 if (((i % 8) == 0) && (i != 0)) {
0298 seq_putc(m, '\n');
0299 }
0300 seq_printf(m, "0x%.4x ",
0301 ((uint16_t*)ahd->seep_config)[i]);
0302 }
0303 seq_putc(m, '\n');
0304 }
0305 seq_putc(m, '\n');
0306
0307 if ((ahd->features & AHD_WIDE) == 0)
0308 max_targ = 8;
0309
0310 for (i = 0; i < max_targ; i++) {
0311
0312 ahd_dump_target_state(ahd, m, ahd->our_id, 'A',
0313 i);
0314 }
0315 return 0;
0316 }