/* * tool for updating the firmware on a scsi terminal server * * Copyright (C) 2001 Kees Cook * cook@cpoint.net, http://outflux.net/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include #include #include #include #include #include #include #include #include #include #include "scsi_iface.h" #include "scsi_tools.h" #include "firmware.h" /* correctly find an STS device */ scsi_info * choose_device(void) { int i; char sgfile[64]; char input[64]; scsi_info * dev; int found; char selection; char choice=' '; char max='A'-1; printf("Scanning for STSs ...\n"); for (;;) { found=0; /* rescan: nothing found yet */ max='A'-1; /* reset our max below A */ selection='A'-1; /* reset our selection too */ /* print our header if we're not selecting a device */ if (choice==' ') { printf("#) Host Chan ID Vendor Product Ver\n"); printf("-- ---- ---- --- ---------- ------------------ ------\n"); } /* search for a LOT of devices... */ for (i=0;i<128;i++) { sprintf(sgfile,"/dev/sg%d",i); if ((dev = scsi_open_name(sgfile))!=NULL) { if (scsi_unitready(dev) && dev->sginfo.lun == 0 && dev->sginfo.scsi_type==TYPE_COMM && (!strcmp(dev->vendor,"CenData ") || !strcmp(dev->vendor,"DigIintl") || !strcmp(dev->vendor,"MOTOROLA")) ) { found=1; /* we found something */ selection++; /* push selection letter forward */ max=selection; /* update max selection */ /* if we didn't select anything, or THIS one, print info */ if (choice==' ' || choice==selection) { printf("%c) %4d,%4d, %2d '%s' '%s' '%s'\n", selection, dev->sginfo.host_no, dev->sginfo.channel, dev->sginfo.scsi_id, dev->vendor, dev->product, dev->version ); /* stop the for loop of devices, we got what we wanted */ if (choice==selection) break; } } /* done looking at device, close it up */ scsi_close(dev); dev=NULL; } } /* quit if there aren't any devices */ if (!found) { printf("No STS devices found!\n"); return NULL; } /* if we selected a device, "dev" isn't NULL */ if (dev) return dev; /* loop until they pick a valid selection */ while (choice<'A' || choice>max) { printf("\nWhich STS do you want to update? (CR aborts) "); fflush(NULL); fgets(input,64,stdin); choice=toupper(input[0]); /* kick up the case */ if (choice=='\n') { return NULL; } printf("\nSTS selected:\n"); } } /* how the hell did we get here? */ return NULL; } /* choose a firmware image and verify it's sanity */ firmware_img * choose_firmware(scsi_info * dev) { char * possible; char input[255]; char devproduct[26]; firmware_img * firmware=NULL; int i; /* for readdir */ DIR * dir; struct dirent * ent; int found=0; /* for fw ver check */ int imgmajor, imgminor, devmajor, devminor; if (!dev) { fprintf(stderr,"choose_firmware got a NULL dev?!\n"); return NULL; } /* get rid of training spaces. Needed for firmware filename generation, and firmware product id comparison */ strncpy(devproduct,dev->product,25); devproduct[24]='\0'; for (i=strlen(devproduct)-1; i>=0 && devproduct[i]==' '; i--) { devproduct[i]='\0'; } if (!(possible=build_firmware_filename(devproduct))) { fprintf(stderr,"Failed to guess at filename?!\n"); return NULL; } while (!firmware) { printf("\nIn current directory, the firmware (*.prm) files are:\n"); if ((dir=opendir("."))) { while ((ent=readdir(dir))!=NULL) { char * ptr; ptr=strstr(ent->d_name,".prm"); if (ptr && ptr[4]=='\0') { found=1; printf(" %10s\n",ent->d_name); } } closedir(dir); } else { perror("opendir"); } if (!found) { printf(" none found!\n"); } printf("\n"); printf("Load which firmware image? (CR = '%s', Q quits) ",possible); fflush(NULL); fgets(input,254,stdin); if (input[0]=='q' || input[0]=='Q' || input[0]=='\0') return NULL; /* tear off the \n */ input[strlen(input)-1]='\0'; /* did they want the default? */ if (input[0]=='\0') strncpy(input,possible,255); printf("\n"); /* bring the file into memory */ if (!(firmware=load_firmware(input))) { fprintf(stderr,"Failed to load firmware.\n"); continue; } /* verify that we have a real STS firmware ... */ if (!verify_image(firmware)) { fprintf(stderr,"This doesn't look like an STS firmware!\n"); unload_firmware(firmware); firmware=NULL; continue; } printf("Image has firmware for the '%s' (version '%s', %d bytes)\n", firmware->unit.name,firmware->unit.fw_ver,firmware->length); /* make SURE the product matches the SCSI device */ if (strcmp(firmware->unit.name,devproduct)) { fprintf(stderr,"*** This image is NOT for the '%s'! ***\n", devproduct); unload_firmware(firmware); firmware=NULL; continue; } /* issue a warning if down-grading the firmware */ devmajor=atoi(dev->version+1); devminor=atoi(dev->version+3); imgmajor=atoi(firmware->unit.fw_ver+1); imgminor=atoi(firmware->unit.fw_ver+3); if ((devmajor==imgmajor && devminor>=imgminor) || (devmajor>=imgmajor)) { char reply[80]; fprintf(stderr,"*** This image (%s) is NOT NEWER than your " "current firmware (%s)! ***\n", firmware->unit.fw_ver,dev->version); fprintf(stderr,"\t\tAre you SURE you want to continue? [y/N] "); fflush(NULL); fgets(reply,79,stdin); if (!(reply[0]=='y' || reply[0]=='Y')) { unload_firmware(firmware); firmware=NULL; continue; } } } return firmware; } int main() { firmware_img * firmware; scsi_info * dev; int rc=FAILED; char buf[80]; printf("stsupdate v1 Feb 13, 2001\n"); for (;;) { if (!(dev=choose_device())) { printf("No device selected. Exiting...\n"); exit(0); } if (!(firmware=choose_firmware(dev))) { printf("No firmware selected. Exiting...\n"); scsi_close(dev); exit(0); } printf("\n*** Do not power off your STS during programming. ***\n"); printf("\nRemember this program might destroy your STS firmware!\n"); printf("Hit enter to start programming... "); fflush(NULL); fgets(buf,79,stdin); if ((rc=upload_now(dev,firmware))==BADSTATE) { fprintf(stderr,"***### YIKES ###***\n"); fprintf(stderr,"*** Your STS failed during firmware upload ***\n"); fprintf(stderr,"*** DO NOT POWER OFF your STS ***\n"); fprintf(stderr,"*** Try again immediately ***\n"); fprintf(stderr,"*** If this continues, you have a new paper-weight ***\n"); } else if (rc==FAILED) { fprintf(stderr, "Sorry, your firmware upload failed. Please " "examine any error message above.\n"); } else { printf("Firmware successfully uploaded!\n"); printf("*** Please power-cycle your STS now. ***\n"); printf("Hit enter when ready... "); fflush(NULL); fgets(buf,79,stdin); } unload_firmware(firmware); scsi_close(dev); } return 0; }