硬盘的FW修改代码

来源:互联网 发布:js网页快捷方式到桌面 编辑:程序博客网 时间:2024/05/22 13:12

以下是SEAGATE的一段升级程序(局部),现在应该还可以使用。从这段程序里s.scsi_command[0]= 0x3B……0x05……0x07可以看到,升级的过程实际是一个传送过程,先把代码送到BUFFER里执行,后面的指令就是状态监视。

硬盘来说是需要专门的方式进行传送升级代码的,不然,你的代码会被硬盘当成DATA写到了盘片上。

编译环境是使用IP *Works! C++Linux Edition

声明:当年很多和SEAGATE硬盘相关的软件大都使用或借鉴这段程序,所以运行的流程在一定程度上和其他的软件有相似的地方,甚至窗口位置都一样。升级FIRMWARE的过程特别简单.
该程序具有版权,请大家不要原封不动的抄,理解了后可以变换变换,除非得到授权才能照抄发布自己的东西。

void download_firmware()
{
SCSI *dl;
int w, key, fh, choice, org_asa, new_asa, n= 0, off= 0;
unsigned bufsize= 8*1024, rv;
char *filename, *p;
long l, j, i, jj, offset;

if (!is_seagate_disk(inq))
message("WARNING !rn"
"rn"
"Download firmware is only tested with Seagate disk drives.");

filename= calloc(1, 128);
if (!filename)
{
printf("Error allocating %u bytes of memoryn", 128);
exit(0);
}

strcpy(filename, config->;download_file);
key= edit_string_window(filename, 70, "Enter firmware file to download");
if (key== KEY_ENTER)
{
fh= open(filename, O_RDONLY|O_BINARY);
if (fh!= -1)
{
w= window_create(-1, 9, 60, 18, BLUE<<4|LIGHTGRAY, BORDER_SINGLE,
_NOCURSOR, BLUE<<4|YELLOW, "Download firmware");

l= filelength(fh);
if (overwrite(inq, "Download firmware to ")== 1)
{
list_select("Download firmware", &off, "Without offset",
"With offset", NULL);
if (off!= -1)
{
org_asa= seagate_asa_level(inq);
gotoxy(1,1);
cprintf("Original ASA level is ASA%urn", org_asa);

if (off== 0) bufsize= 0;

dl= scsi_init(bufsize);
dl->;s.host_adapter= inq->;s.host_adapter;
dl->;s.target_id= inq->;s.target_id;
dl->;s.lun= inq->;s.lun;

dl->;s.scsi_command[0]= 0x3B;
if (off== 0)
{
p= farmalloc(l);
if (p== NULL)
{
message("Error allocating %lu bytes", l);
einde(-1);
}

dl->;s.scsi_command[1]= 0x05; 
dl->;s.data_buffer= p;
dl->;s.data_buffer_length= l;
}
else
dl->;s.scsi_command[1]= 0x07;

*(unsigned long *)&dl->;s.scsi_command[5]=
swaplong(dl->;s.data_buffer_length);

if (off== 1)
{
offset= 0;
j= l / bufsize;
jj= l % bufsize;
gotoxy(1,3);
cprintf("%lu blocks of %uK and %lu bytesrn",
j, (bufsize >;>; 10), jj);
cprintf("Block:");
for (i= 0; i < j; i++)
{
_dos_read(fh, dl->;s.data_buffer, bufsize, &rv);
*(unsigned long *)&dl->;s.scsi_command[2]=
swaplong(offset);
if (rv== bufsize)
scsi_execute(dl, 1);
else
{
message("Error while reading firmware file");
einde(-1);
}

gotoxy(8,4);
cprintf("%lu", i);
offset+= rv;
}

if (jj)
{
gotoxy(20,3);
_dos_read(fh, dl->;s.data_buffer, jj, &rv);
*(unsigned long *)&dl->;s.scsi_command[2]=
swaplong(offset);
*(unsigned long *)&dl->;s.scsi_command[5]=
swaplong(rv);
if (rv== jj)
scsi_execute_bg(dl);
else
{
message("Error while reading firmware file");
einde(-1);
}

gotoxy(26,4);
cprintf("%u", i);
offset+= rv;
}
}
else
{
cprintf("Reading file %s, %lu KB", filename, l >;>; 10);
rv= file_read_into_memory(fh, p, l);
if (rv)
{
message("Error while reading firmware file");
einde(-1);
}
scsi_execute_bg(dl);
}

gotoxy(1,4);
clreol();
cprintf("Download status :");

n= 0;
while(dl->;s.status== 0)
{
gotoxy(18,4);
putch(wiekje[n++]);
if (!wiekje[n]) n= 0;
gotoxy(19,4);
cprintf("%-10.10s", aspi_status_name(dl->;s.status));
delay(250);
}

gotoxy(18,4);
putch(' ');
gotoxy(19,4);
cprintf("%-10.10s", aspi_status_name(dl->;s.status));

if (dl->;s.status!= 1)
{
gotoxy(1,5);
print_sense_info_short(dl);
}
else
{
gotoxy(1,6);
cprintf("Waiting for unit");
wait_unit_ready(inq);

new_asa= seagate_asa_level(inq);
gotoxy(1,6);
clreol();
cprintf("New ASA level is ASA%u", new_asa);

if (org_asa!= new_asa)
{
message("You upgraded your drive to a newrn"
"ASA level, drive needs low level format !rn"
/*大家注意这点,升级是有风险的,这个信息只是其中一个很小的风险,由于ASA级别的改变,需要你低级格式化硬盘,哈哈数据没啦!
SEAGATE厂的ASA为2。其他计算机大厂的ASA有的为0有的为1……,自己找些资料参考吧。
*/ 
"rn"
"%s", fortune(fun_message));
}
}

if (off== 0)
{
dl->;s.data_buffer= NULL;
dl->;s.data_buffer_length= 0;
farfree(p);
}
scsi_destroy(dl);

pause();
}
}

close(fh);
window_destroy(w);
strcpy(config->;download_file, filename);
cfg_save();
}
else
message("Error opening file %snr->;%s", filename, sys_errlist[errno]);
}

free(filename);
SEAGATE ST336607的部分模式页在这里,自己修改响应的值再写回去就可以了。
04 3c d9 40 00 00 02 00
01 0a c8 0b ff 00 00 00 05 00 27 10 
02 0e 00 00 00 0a 00 00 00 00 00 00 10 00 00 00 
03 16 11 aa 00 00 00 08 00 00 02 d0 02 00 00 01 00 66 00 66 40 00 00 00 
04 16 00 c2 bf 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 27 31 00 00 
07 0a 08 0b ff 00 00 00 00 00 27 10 
08 12 10 00 ff ff 00 00 ff ff ff ff 00 10 00 00 00 00 00 00 
0a 0a 00 00 00 00 00 00 00 00 03 00 
19 06 01 00 ff ff 00 00 
1a 0a 00 03 00 00 00 01 00 00 00 04 
1c 0a 88 04 00 00 8c a0 00 00 00 00
下面给你一段参考汇编程序,希自己的硬盘改成自己的名字望对你有用。


.MODEL large, C
.DATA

.CODE

extrn AspiEntryPoint:dword
public SRBexec

SRBexec PROC C, segm:WORD, ofs:WORD

mov ax, segm
push ax
mov ax, ofs
push ax
call DWORD PTR [AspiEntryPoint]
add sp, 4
ret
SRBexec ENDP

public swaplong

swaplong PROC C, long1,long2:WORD

mov ax, long2
xchg al, ah
mov dx, long1
xchg dl, dh

ret
swaplong ENDP

public swapint

swapint PROC C, int1:WORD

mov ax, int1
xchg al, ah

ret
swapint ENDP

end有个文件名叫sgdskfl.c,是INTEL的工程师Andy cress写的,算法上和SEAGATE的大致相同,另外还包括很多其他可移动SCSI设备和流SCSI设备的方案

Andy Cress的编程风格很好,具有很多注释,大家应该很容易看懂。不过由于页面显示程序的缘故,所有程序代码左边的空格均无效了,因此全靠左显示,给大家浏览带来了不便。如果希望浏览更好看的代码,请访问[STOL]存储社区


/*-------------------------------------------------------------------------- 
Filename : sgdskfl.c
Abstract : SCSI Generic Disk Firmware Load tool
Operation System: Linux 2.2 or greater
Copyright ? Intel Corporation 2001
Author: Andy Cress 
----------- Change History -----------------------------------------------
05/01/01 v0.70 ARCress created 
07/17/01 v0.91 ARCress added code to download servo also
added write_buffers code to do multi-part dl.
08/08/01 v0.92 ARCress fixed write_buffers logic for IBM disks.
09/05/01 v0.93 ARCress message cleanup
09/28/01 v0.94 ARCress turn off sg_debug in afterdl
10/15/01 v0.95 ARCress fixed IBM chunk size
10/30/01 v1.0 ARCress cleanup includes & indent -kr 
11/09/01 v1.0 ARCress enlarged devstat2 from 80 to 120 for overrun 
11/14/01 v1.0 ARCress added default directory for image files.
04/11/02 v1.1 ARCress path changes for log & image files,
set do_numeric=1 default
05/08/02 v1.3 ARCress tune sg_debug level down to 5 by default
08/15/02 v1.4 ARCress moved common subroutines to sgcommon
added more usage messages
09/03/02 v1.5 ARCress streamline display for errors in get_scsi_info 
01/08/03 v1.6 ARCress include Quantum in getimage:fscanmodel.
----------- Des cription --------------------------------------------------
sgdskfl 
Sequence of events for this utility:
* List each device on the system with firmware versions.
* User selects a device for firmware load (automatic if using -m)
* Read the firmware image file for the selected disk and verify that it is 
valid. 
* Verify that the disk is present and ready
* Close all open files, flush the adapter, sync any data to the SCSI disks. 
* Write the firmware image to the disk using a 'write buffer' SCSI command
with large reserved buffer or scatter/gather.
* Wait 5 (or specified number) seconds
* Verify that the disk comes ready again using SCSI test_unit_ready commands,
and start_unit or scsi_reset to recover if not.
* If the '-m' option was used, repeat writing the firmware for each disk of 
this model.
sgdskfl [-e -m diskmodel -f imagefile -t secdelay -x] 
Options:
-e Do not write to any files. Usually a log file (sgdskfl.log) is created
and written to, up until the firmware download begins on root.
-m Automatically download all drives that match this model string.
Note that this option will initiate a reboot after it is done, 
unless option u is also specified.
-f Specify this filename for the firmware image. Normally, this option is 
not used and the filename is formed using the first 8 characters of the 
model, with the ".lod" extension. For example: "st39140w.lod". 
Note that this utility uses the raw firmware image without any added 
headers.
-t Specifies the number of seconds to delay after the firmware is written 
and the program attempts to test if the unit is ready again. 
Default is 10 seconds.
-r Recover a non-ready drive by updating its firmware.
Don't test if the drive is ready or not.
-x Outputs extra debug messages
-d Specify a unix device name
----------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
Copyright ? 2002, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:
a.. Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer. 
b.. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution. 
c.. Neither the name of Intel Corporation nor the names of its contributors 
may be used to endorse or promote products derived from this software 
without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
-------------------------------------------------------------------------*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "sgsub.h"
#include "sgcommon.h"

/* External Functions prototypes */
extern void setbuf(FILE * stream, char *buf);
extern int errno;
extern char fdebugsub; /* used in sgsub.c */
extern FILE *dbgout; /* used in sgsub.c */

#define EBUFF_LEN 80
#define MAX_ERRORS 4

/* Global data definitions */
char progver[] = "1.6"; /* program version */
char *progname = "sgdskfl"; /* program name */
char logfile[] = "/var/log/sgdskfl.log"; /* log filename */
char fwsufx[] = ".lod"; /* suffix for firmware image filenames */
char model[20] = ""; /* default model string */
char fsetfile = 0;
char fwfile[20] = "default"; /* default firmware filename (8.lod) */
char defdir[30] = "/usr/share/scsirastools/"; /*default directory for fw files*/
char devname[80] = "/dev/sda"; /* UNIX device name (w path) */
char svfile[20] = "default"; /* default servo filename (8.tms) */
int sdelay = 10; /* num sec to delay before TUR */
FILE *fdlog = NULL; /* log file des criptor */
FILE *fdmsg; /* file des criptor for messages */
char fautomodel = 0; /* =1 to automatically do all of a model */
char filesok = 1; /* =1 if ok to write to files */
char fdebug = 0; /* =1 for debug messages */
char fdoreset = 0; /* =1 if need to do reset for this drive */
char flogopen = 0; /* =1 if log file is open */
char fnotur = 0; /* =1 to not try TUR */
char fdevname = 0; /* =1 if device name specified */
int do_numeric = 1; /* NUMERIC_SCAN_DEF; */
uchar sense_buffer[80]; /* buffer for sense data */
char output[132]; /* message output buffer */
char output2[80]; /* extra message output buffer */
uchar devstat[80]; /* used for inquiry & device status */
uchar devstat2[120]; /* used for Seagate inquiry2 & Mylex stat */
uchar disk_buffer[0x200]; /* 512 bytes, used for misc scsi data */
uchar *image_buffer; /* malloc'd firmware image buffer */
uchar *servo_buffer; /* malloc'd servo buffer */
int idev = 0;
int ndev = 0;
DEVLIST_TYPE devlist[32];
char *devtype_array[11] = {
"Disk ",
"Tape ",
"Printer",
"Procesr",
"WORM ",
"CD-ROM ",
"Scanner",
"Optical",
"Med Chg",
"Comm ",
"Unknown"
};

/* Local subroutines */
int writeimage(int idx, uchar * imgbuf, ulong len, char fservo);
ulong getimage(int idx, uchar ** pbuf, char fservo);
int beforedl(int idx, int *pnumrdy);
int afterdl(void);

int main(int argc, char **argv)
{
int i, c, idx;
char response = 0;
ulong size; /* size of fw */
ulong size_sv; /* size of servo */
int runl;
short sts, rc;
ulong ltime1;
char fname[64];
char ebuff[EBUFF_LEN];
int sg_fd;
int flags;
int res, k;
int eacces_err = 0;
int num_errors = 0;
DEVFS_LIST devfs_components = {0,0,0,0,0};

// progname = argv[0];
fdmsg = stdout; /* set default fdmsg */
while ((c = getopt(argc, argv, "enxrf:m:t:d:?")) != EOF)
switch ? {
case 'e':
filesok = 0;
break;
case 'x':
fdebug = 1;
break;
case 'r':
fnotur = 1;
break;
case 'n':
do_numeric = 0;
break;
case 'f':
strcpy(fwfile, optarg);
fsetfile = 1;
break;
case 'm':
fautomodel = 1; /* automatically do all of this model */
strcpy(model, optarg);
break;
case 't':
sdelay = atoi(optarg); /* time to delay */
break;
case 'd':
strcpy(devname, optarg); /* specify a unix device name */
fdevname = 1;
break;
case '?':
default:
printf("Usage: %s [-m diskmodel -f imagefile -t secdelay -enrx]n",
progname);
printf(" -m Automatically download all drives that match this model stringn");
printf(" -f Specify filename for firmware image instead of defaultn");
printf(" -t Time in seconds to delay after the firmware is written, default 10n");
printf(" -n Turn off Numeric, use alpha device names insteadn");
printf(" -e Do not write to any files, so don't use the log filen");
printf(" -r Recover a non-ready drive by updating its firmwaren");
printf(" -x Outputs extra debug messagesn");
exit(1);
}
/* only run this as superuser */
i = geteuid();
if (i >; 1) {
printf("Not superuser (%d)n", i);
exit(1);
}
/* check for run-level 1 */
{
runl = 1;
/* how to check this? */
if (fdebug) {
/*DEBUG*/ printf("sdelay = %d secn", sdelay);
printf("run-level = %dn", runl);
}
}
if (runl != 1) { /* show warning if not run level 1 */
printf
("Warning: Make sure disks are inactive during firmware downloadn");
// dont exit, just give a warning.
}
/* open log file */
if (filesok)
fdlog = fopen(logfile, "a+");
if (fdlog == NULL) {
flogopen = 0;
filesok = 0;
fdlog = stderr;
} else { /* logfile open successful */
flogopen = 1;
time((time_t *) & ltime1);
fprintf(fdlog, "n--- %s v%s log started at %s", progname, progver,
ctime((long *) fprintf(fdlog, "model: %sn", model);
fprintf(fdlog, "fw file: %sn", fwfile);
}
fdebugsub = fdebug;
dbgout = fdlog;
/* loop to display disk choices and do downloads */
while (1) {
/* display header */
printf("n");
printf(" %s utility v%s for SCSI disksn", 
progname, progver);
printf
(" ******************************************n");
if (flogopen)
printf("Log file %s is open, debug=%dn", logfile, fdebug);
printf
("nNum Name [bus] Type Vendor Device_Model FW__ Serial#_ Servo___n");
/* get SCSI Device Info */
idev = 0;
flags = O_RDWR; /* could use OPEN_FLAG if read-only. */
num_errors = 0;
for (k = 0; (k < 1000) && (num_errors < MAX_ERRORS); ++k) {
// if (fdebug) fprintf(fdlog,"k=%d, num_errors=%dn", k, num_errors);
if (fdevname) { /* user-specified device name */
strcpy(fname, devname);
k = 1000;
} else {
make_dev_name(fname, k, do_numeric, &devfs_components);
if (devfs_components.all_leaves_searched != 0) {
devfs_components.all_leaves_searched=0;
break;
}
}
sg_fd = open(fname, flags | O_NONBLOCK);
if (fdevname && fdebug)
fprintf(fdlog, "k=%d, %s open, sg_fd = %dn", k, fname,
sg_fd);
if (sg_fd < 0) {
if (EBUSY == errno) {
printf("%s: device busy (O_EXCL lock), skippingn",
fname);
continue;
} else if ((ENODEV == errno) || (ENOENT == errno) ||
(ENXIO == errno)) {
++num_errors;
continue;
} else { /* open failed with other error */
if (EACCES == errno)
eacces_err = 1;
sprintf(ebuff, "Error opening %s ", fname);
perror(ebuff);
++num_errors;
continue;
}
}
sts = get_scsi_info(sg_fd, idev, fname,1);
if (sts) {
fprintf(fdlog, "device %s failed with sts = %d, skipn",
fname, sts);
} 
if (sg_fd >; 0) {
res = close(sg_fd);
if (res < 0)
fprintf(fdmsg, "Error closing %s, errno = %dn",
fname, errno);
else
devlist[idev].sgfd = 0; /* set in get_scsi_info() */
}
idev++;
} /*end loop */
ndev = idev;
if (ndev == 0 && errno == ENODEV) { /* CONFIG_CHR_DEV_SG != y ? */
sprintf(output,
"Cant open any SCSI devices.nMake sure CONFIG_CHR_DEV_SG is set in /usr/src/linux/.confign");
showit(output);
quit(1);
}
else if (ndev == 0) {
sprintf(output,"Cant open any sg SCSI devices, errno = %dn",errno);
if (errno == ENOENT) 
strcat(output,"Try option -n to change /dev/sg* device namesn");
showit(output);
}
printf("nEnter Selection ('d' to download, 'q' to quit) : ");
if (fautomodel) {
response = 'd';
printf("%cn", response);
} else {
response = get_func();
}
if (response == 'q' || response == 'Q')
quit(0);
else if (response == 'd' || response == 'D') { /* do download */
if (fautomodel)
i = get_mdev(model); // get first matching dev
else
i = get_idev(); /* get the device index that the user picks */
if (i == 0xff)
printf("Index out of range, try again.n");
else { /*index ok */
int numrdy;
idx = i; /* first disk to download */
size = getimage(idx, ?_buffer, 0); /* read in the firmware image */
size_sv = getimage(idx, &servo_buffer, 1); /* read in the servo image */
if (fdebug) {
/*DEBUG*/ fprintf(fdlog, "size = %ldn", size);
if (size != 0)
fprintf(fdlog, "imgbuf: %02x %02x %02x %02x n",
image_buffer[0], image_buffer[1],
image_buffer[2], image_buffer[3]);
if (!fautomodel) {
do_pause();
}
}
if (size == 0)
idx = ndev; /* error, skip download */
else { /* image ok */
rc = beforedl(idx, &numrdy);
if (numrdy == 0)
idx = ndev;
/* download the image to each matching disk */
for (i = idx; i < ndev; i++) {
if (devlist[I.fdoit) {
struct SCSI_INQUIRY *scsi_inq;
char fservo;
/* decide which download method to use */
scsi_inq =
(struct SCSI_INQUIRY *) devlist[I.inq;
if ((devlist[I.inq[0] & 0x1F) == 1) { /* devtype == tape */
if (strncmp
((char *) scsi_inq->;vendorid,
"SEAGATE", 7) != 0)
fservo = 3; /* Seagate tapes use split buffer method 3 */
/* Tecmar, Travan, Wangtek, WangDAT tapes use method 2 */
else
fservo = 2; /* use split buffer method 2 */
}
else
if (
(strncmp
((char *) scsi_inq->;vendorid, "IBM",
3) == 0)
&&
(strncmp
((char *) scsi_inq->;productid, "ST",
2) != 0))
/* for all IBM disks, except Seagate OEM */
fservo = 4; /* IBM disks use split buffer method X */
else
fservo = 0; /* normal, all one buffer */
if (size >; 0) { /* flash firmware */
rc =
writeimage(i, image_buffer, size,
fservo);
free(image_buffer); /*allocated in getimage() */
if (fdebug && rc != 0) {
showit((char *) disk_buffer); /*writes saved messages */
quit(rc);
}
}
if (size_sv >; 0) { /* flash servo */
rc =
writeimage(i, servo_buffer, size_sv,
1);
free(servo_buffer); /*allocated in getimage() */
}
}
if (!fautomodel)
i = ndev; /* only do one if interactive */
} /*endfor each disk */
rc = afterdl();
} /*endif image ok */
} /*end else index ok */
} /*end else do download */
else { /* response not d or q */
printf("Invalid input [%c], enter 'd' or 'q'.n", response);
}
if (fautomodel) { /* then done */
if (0) { /* if root is down and likely to hang otherwise, */
printf("Rebooting ...n");
sleep(3);
// /* do reboot without shutdown */
} else
quit(0); /* normal exit, successful */
} else { /* interactive, go to menu again */
do_pause();
}
} /*end while(1) */
} /*end main() */

ulong getimage(int idx, uchar ** pbuf, char fservo)
{
ulong filsz;
FILE *fdimg;
struct stat statbuf;
struct SCSI_INQUIRY *scsi_inq;
char modelx[20];
char *filenm;
char fullfilenm[80];
char *buf;
int i, rc;
*pbuf = NULL;
scsi_inq = (struct SCSI_INQUIRY *) devlist[idx].inq;
if (fautomodel)
strncpy(modelx, model, strlen(model));
else
strncpy(modelx, (char *) scsi_inq->;productid, 16);
for (i = 0; i < 16; i++) /* eliminate trailing spaces */
if (modelx[I == ' ')
break;
modelx[I = 0; /*stringify */
if (fdebug) {
/*DEBUG*/ fprintf(fdlog, "get image idx=%dn", idx);
fprintf(fdlog, "fw file: %sn", fwfile);
fprintf(fdlog,
"___________ 0....+....1....+....2....+....3....+....4n");
fprintf(fdlog, "scsi_inq[8]: %sn", &devlist[idx].inq[8]);
}
if (fservo != 1) {
sprintf(output, "Selected %d: [%d:%d] %sn", idx,
devlist[idx].chn, devlist[idx].tgt, scsi_inq->;vendorid);
showit(output);
}
if (!fsetfile) { /* build the default filename */
for (i = 0; i < 8; i++) { /*limit filename to 8 chars */
if (modelx[I == ' ')
break;
else
fwfile[I = tolower(modelx[I);
}
fwfile[I = 0;
strcat(fwfile, fwsufx);
}
if (fservo == 1) {
char *p;
filenm = fwfile;
strcpy(svfile, fwfile); /* servo filename */
p = strrchr(svfile, '.'); /* find last '.' in filename */
strcpy(++p, "tms"); /* skip '.', add new suffix */
filenm = svfile;
} else
filenm = fwfile;
if (fdebug)
fprintf(fdlog, "fw filename: %sn", filenm);
/* open file */
fdimg = fopen(filenm, "r"); /* try current directory */
if (fdimg == NULL) { /* if error, set default directory */
strcpy(fullfilenm,defdir);
strcat(fullfilenm,filenm);
filenm = fullfilenm;
}
fdimg = fopen(filenm, "r"); /* try default directory */
if (fdimg == NULL) {
if (fservo == 1) {
if (fdebug)
fprintf(fdlog, "Cannot open %s, errno = %dn", filenm,
errno);
sprintf(output, "No servo imagen");
} else
sprintf(output, "Cannot open %s, errno = %dn", filenm, errno);
showit(output);
return (0); /* size = 0 */
}
/* get image file size */
if (fstat(fileno(fdimg), &statbuf) < 0) {
sprintf(output, "Can't get size of %s, errno = %dn", filenm,
errno);
showit(output);
fclose(fdimg);
return (0); /* size = 0 */
}
filsz = statbuf.st_size;
buf = malloc(filsz);
if (buf == NULL) {
sprintf(output,
"Cannot allocate %ld bytes of memory, errno = %d.n",
filsz, errno);
showit(output);
fclose(fdimg);
return (0); /* size = 0 */
}
/* read in the image file */
sprintf(output, "Reading image file %s, size = %ldn", filenm, filsz);
showit(output);
rc = fread(buf, filsz, 1, fdimg);
if (rc == -1) {
sprintf(output, "Error reading %s, errno = %d.n", filenm, errno);
showit(output);
fclose(fdimg);
free(buf);
return (0); /* size = 0 */
}
if (fservo != 1) {
char fscanmodel;
fscanmodel = 0;
if (strncmp((char *) scsi_inq->;vendorid, "SEAGATE", 7) == 0) {
if (modelx[7] == 'W')
modelx[7] = 'N'; /*always match with narrow */
modelx[8] = 0; /* truncate to 8 chars for search */
fscanmodel = 1;
} else if (strncmp((char *) scsi_inq->;vendorid, "IBM", 3) == 0)
fscanmodel = 1;
else if (strncmp((char *) scsi_inq->;vendorid, "MAXTOR", 6) == 0)
fscanmodel = 1;
else if (strncmp((char *) scsi_inq->;vendorid, "QUANTUM", 7) == 0)
fscanmodel = 1;
/* HITACHI and FUJITSU only have partial model strings to match */
if (fscanmodel) { /* scan image buffer for model(productid) */
/* A variable offset in the file has a list of the target models. */
rc = findmatch(buf, filsz, modelx, strlen(modelx), 1); /*also ignore case */
if (rc == -1) {
sprintf(output, "Image does not match model %sn", modelx);
showit(output);
fclose(fdimg);
free(buf);
return (0); /* size = 0 */
}
if (fdebug) {
sprintf(output, "Image file matches model %sn", modelx);
showit(output);
}
} /*endif scanmodel */
}
/*endif not servo */
*pbuf = buf;
fclose(fdimg);
return (filsz);
} /*end getimage() */

int write_buffers(int sgfd, uchar * buf, ulong len, uchar fservo)
{
int sts;
ulong j, sz_left;
ulong max_chunk;
uchar save_mode;
uchar bufid;
uchar ebuf[20];
if (fservo >;= 2) {
if (fservo == 3) { /* Seagate tapes */
max_chunk = 0x4000;
save_mode = 0x07;
} else if (fservo == 2) { /* other tapes */
max_chunk = 0x8000;
save_mode = 0x05;
} else // if (fservo == 4) { /* IBM disks */
{
max_chunk = 0x8000; /* get this from mode page C7, bytes 16-18 */
save_mode = 0x05;
if (fdebug)
fprintf(fdlog, "IBM split buffer mode, chunk size = %ldn",
max_chunk);
j = 0;
sz_left = len;
bufid = 0;
while (sz_left >; max_chunk) {
/* Note that it uses mode 05 for every chunk, not just last one */
sts =
write_buffer(sgfd, &buf[j], max_chunk, save_mode,
bufid);
if (sts != 0) {
unsigned int k, a, q;
int rc;
rc = get_sense(sts, ebuf);
k = ebuf[2] & 0x0f; /*Sense Key */
a = ebuf[12];
/*ASC*/ q = ebuf[13];
/*ASCQ*/
sprintf(output, "wb sense error: %x/%x/%xn", k, a,
q);
showit(output);
if (k == 03 && a == 0x30)
printf("Overlay upload errorn");
else if ((k == 2 || k == 3 || k == 4) &&
(a == 0x40 && q <= 0x85))
printf("Microcode Load Failuren");
return (sts);
}
sz_left -= max_chunk;
j += max_chunk;
bufid++;
}
sts = write_buffer(sgfd, &buf[j], sz_left, save_mode, bufid);
return (sts);
} /*endelse IBM disks */
/* Handle the split buffer scheme */
/* This assumes that the start address is zero for all. */
bufid = 0;
j = 0;
sz_left = len;
while (sz_left >; max_chunk) {
sts = write_buffer(sgfd, &buf[j], max_chunk, 0x04, bufid);
if (sts != 0)
return (sts);
sz_left -= max_chunk;
j += max_chunk;
}
sts = write_buffer(sgfd, &buf[j], sz_left, save_mode, bufid);
}
/*endif split buffer scheme */
else { /* fservo == 0, or fservo == 1 */
/* Send it all as one big buffer */
sts = write_buffer(sgfd, buf, len, 0x05, 0L);
}
return (sts);
} /* end write_buffers() */


int writeimage(int idx, uchar * imgbuf, ulong len, char fservo)
{
int sts;
int devfd;
int isave;
ulong ltime, ltime1, ltime2;
ulong ltime3;
int i, rc, rcdl;
int k, a, q;
char *tag;
uchar ch, dv;
isave = idx;
rcdl = 0;
/* Download firmware to this disk */
{
rcdl = 0;
fdoreset = 0;
if (!fautomodel)
idx = isave; /* only do selected disk */
devfd = devlist[idx].sgfd;
ch = devlist[idx].chn;
dv = devlist[idx].tgt;
if (devlist[idx].fdoit == 1) {
if (fautomodel) {
/* Sometimes next device may have a unit attention/reset check 
* condition pending, so clear that first before the write_buffer. 
*/
sts = test_unit_ready(devfd, 0);
if (fdebug)
fprintf(fdlog, "Extra test_unit_ready sts = %xn",
sts);
}
time((time_t *) & ltime1); // get the start time
/* start the firmware download */
if (fservo == 1)
tag = "Servo";
else
tag = "Firmware";
sprintf(output, "Downloading %s image to disk %d %s",
tag, idx, ctime((long *) // ctime outputs a 'n' at end
showit(output);
sts = write_buffers(devfd, imgbuf, len, fservo);
if (sts) {
rcdl = sts;
sprintf(output, "[%d] Error %d in writing buffern", idx,
sts);
showit(output); // fdlog closed
if (fdebug || !fautomodel) {
return (rcdl); // (only if debug on)
}
}
if (fautomodel && rcdl != 0) {
/* Save error for logging later */
sprintf(output, "[%d] %s download error, status = 0x%xn",
idx, tag, rcdl);
strcat((char *) disk_buffer, output);
/* Try to restart the drive, even if the download failed. */
return (rcdl); /*skip to next one if error */
}
// Test if Unit is Ready again
sprintf(output, "Waiting for disk to come ready again ");
showit(output);
sleep(sdelay); /* wait for the drive to reset and come ready */
for (i = 0; i < 30 && sts; i++) {
// sts = restart_device(devfd,devlist[idx].dstat);
sts = test_unit_ready(devfd, 0);
if (sts == SCHECK_CND) { /* check for certain key/asc/ascq values */
rc = get_sense(sts, sense_buffer);
k = sense_buffer[2] & 0x0f; /*Sense Key */
a = sense_buffer[12];
/*ASC*/ q = sense_buffer[13];
/*ASCQ*/ if (k == 2 && a == 4 && q == 2) {
/* 02-04-02 means it needs a start command, so issue it. */
sts = start_unit(devfd);
if (fdebug) {
/*DEBUG*/
sprintf(output, "nStart Unit: sts=%d, ",
sts);
showit(output);
}
} /*endif 02-04-02 */
} /*endif sts */
else {
k = 0;
a = 0;
q = 0;
}
if (fdebug) {
sprintf(output, "[%d: %d %d %d]", sts, k, a, q);
showit(output);
}
fprintf(fdmsg, ".");
sleep(3);
} /* end TUR for loop */
showit("n");
// filesok = 1; /* afterdl allows files to be opened again */
if (sts < 0) { /* still not ready, needs a reset */
fdoreset = 1;
sts = scsi_reset(devfd, 3);
if (sts) {
sprintf(output,
"Error %d during SCSI reset of channeln",
sts);
strcat((char *) disk_buffer, output);
} else {
sprintf(output,
"SCSI reset of channel %d successfuln", ch);
strcat((char *) disk_buffer, output);
}
if (fdebug)
do_pause();
sleep(1);
sts = test_unit_ready(devfd, 0); /*first may get check condition */
sts = test_unit_ready(devfd, 1);
}
if (sts) { /* TUR status reports not ready */
rcdl = 0x1000 | sts;
sprintf(output,
"[%d] Did not come ready after download, (%d)n",
idx, sts);
showit(output); // fdlog closed, so ok
} /*endif not ready */
else { /* successful download */
sprintf(output, "[%d] Successful %s downloadn", idx, tag);
showit(output); // fdlog closed, so ok
}
if (fdebug) {
time((time_t *) & ltime3); // get the interval time into ltime3
sprintf(output,
"[%d] write_buffer complete, sts = 0x%x, elapsed secs %02ldn",
idx, rcdl, ltime3 - ltime1);
showit(output);
}
/* Set the timeout shorter. */
k = 500;
sts = ioctl(devfd, 0x2201, &k); /* SG_SET_TIMEOUT */
// if (sts < 0) just continue
// First SCSI command after this may time out, so send a dummy command.
sts = scsi_inquiry(devfd, devstat, 80); // do a dummy inquiry
if (fdebug)
fprintf(fdmsg, "dummy inq sts = %dn", sts); // should be ok now
if (sts != 0)
rcdl = 0x3000 | sts; // use status from inquiry 
/* Dont make a device online if it was offline before we started. */
sts = test_unit_ready(devfd, 0); /*first may get check condition */
if (fdebug)
fprintf(fdmsg, "dummy tur sts = %dn", sts); // should be ok now
/* may get 06/29/04 here */
/* Set the timeout shorter. */
k = 6000;
sts = ioctl(devfd, 0x2201, &k); /* SG_SET_TIMEOUT */
// if (sts < 0) just continue
time((time_t *) & ltime2); // get the end time into ltime2
ltime = ltime2 - ltime1; // total time in seconds
ltime1 = ltime / 3600; // num hours
ltime = ltime % 3600; // remainder, minutes & seconds
sprintf(output, "tt elapsed time %02ld:%02ld:%02ldn",
ltime1, ltime / 60, ltime % 60);
showit(output); // fdlog closed, so ok
/* save result for logging later */
sprintf(output,
"[%d] %s download complete, status = 0x%x, elapsed time %02ld:%02ld:%02ldn",
idx, tag, rcdl, ltime1, ltime / 60, ltime % 60);
strcat((char *) disk_buffer, output);
if ((rcdl & 0x0FFF) == SCHECK_CND) {
sprintf(output, " Sense data: %02x %02x %02xn",
sense_buffer[2] & 0x0f, sense_buffer[12],
sense_buffer[13]);
strcat((char *) disk_buffer, output);
}
if (fdebug && rcdl != 0) {
return (rcdl); /* return (only if debug on) */
}
if (!fautomodel)
idx = ndev; /* end loop */
} /*endif fdoit */
} /*endfor each disk */
return (rcdl);
} /*end writeimage() */

int beforedl(int idx, int *pnumrdy)
{
struct SCSI_INQUIRY *scsi_inq;
int sts;
int sgfd;
int isave, nrdy;
char *pl;
int i, rc, rcdl;
int k, a, q;
int openflags;
char *fname;
int dbglvl;
isave = idx;
nrdy = 0;
sts = 0;
rcdl = 0;
openflags = O_RDWR; /* | O_NONBLOCK; */

/* if fautomodel, use global model from optarg */
if (!fautomodel) {
scsi_inq = (struct SCSI_INQUIRY *) devlist[idx].inq;
strncpy(model, (char *) scsi_inq->;productid, 8);
model[8] = 0; /*stringify */
}
for (idx = 0; idx < ndev; idx++) {
if (!fautomodel)
idx = isave; /* only do selected disk */
fname = devlist[idx].fname;
sgfd = open(fname, openflags); /* open blocking */
if (sgfd < 0) {
printf("%s: open error, errno = %dn", fname, errno);
return (errno);
}
devlist[idx].sgfd = sgfd;
if (fdebug) dbglvl = 10;
else dbglvl = 5;
sts = set_sg_debug(sgfd, dbglvl);
if (sts) {
sprintf(output, "[%d] cant set debug level %d, sts = %d", 
idx, dbglvl, sts);
showit(output);
}
scsi_inq = (struct SCSI_INQUIRY *) devlist[idx].inq;
if (fdebug)
/*DEBUG*/
fprintf(fdlog,
"Doing Test Unit Ready on idx = %d, model=%sn",
idx, model);
if (strncmp(model, (char *) scsi_inq->;productid, 8) == 0) { /* do only ones of the same disk product id */
sts = test_unit_ready(sgfd, 0);
if (sts == SCHECK_CND) { /* not ready initially, try to make it ready */
i = get_sense(sts, sense_buffer);
k = sense_buffer[2] & 0x0f; /*Sense Key */
a = sense_buffer[12];
/*ASC*/ q = sense_buffer[13];
/*ASCQ*/ if (k == 2 && a == 4 && q == 2) {
/* 02-04-02 means it needs a start command, so issue it. */
sts = start_unit(sgfd);
if (fdebug) {
/*DEBUG*/ printf("nStart Unit: sts=%d, ", sts);
if (sts == SCHECK_CND) {
rc = get_sense(sts, sense_buffer);
printf("sense data: %x %x %xn",
sense_buffer[2] & 0x0f,
sense_buffer[12], sense_buffer[13]);
}
}
} /*endif 02-04-02 */
sts = test_unit_ready(sgfd, 1); /* try again */
}
if (sts) {
sprintf(output, "[%d] Error %d from Test Unit Readyn",
idx, sts);
showit(output);
devlist[idx].fdoit = 0;
if (fnotur) {
devlist[idx].fdoit = 1;
nrdy++;
}
} else {
devlist[idx].fdoit = 1;
sprintf(output, "Device [%d] is ready for downloadn",
idx);
showit(output);
nrdy++; /* number ready to download */
}
} else
devlist[idx].fdoit = 0; /* not same product id */
if (!fautomodel)
idx = ndev; /* end loop */
} /* end for devlist TUR loop */
*pnumrdy = nrdy; /* set return value */
if (nrdy == 0) {
sprintf(output, "There are no ready devices for model %s.n",
model);
showit(output);
return (sts);
} else {
if (nrdy >; 1)
pl = "s";
else
pl = "";
sprintf(output, "Starting download process for %d disk%s.n", nrdy,
pl);
showit(output);
}
closelog(); /* sets flogopen to false */
filesok = 0; /* allows files to be opened again */
fflush(fdmsg); /* flush stdout/stderr for messages */
setbuf(fdmsg, NULL); /* set for unbuffered writes */
sync();
sync(); /* write all UNIX buffers to disk */
sleep(2);
/* can't have any more disk IOs from here on */
if (0) { /* fumntroot) *//* unmount root by default, skip it if user says not to. */
fprintf(fdmsg, "Unmounting root ...");
// rc = uadmin(4, 128, 0); /* unmount root fs */
if (rc == 0)
fprintf(fdmsg, "donen");
else
fprintf(fdmsg, "rc = %dn", rc);
// frootdown = 1; 
}
/* Take all drives offline first if specified. */
disk_buffer[0] = 0; /* used for messages later */
return (rcdl);
} /*end beforedl() */


int afterdl(void)
{
int i, sts;
sts = 0;
/* Bring all drives online again if raid */
/* done, all drives should be ready now */
filesok = 1; /* allows files to be opened again */
showit((char *) disk_buffer); /* writes saved messages */
for (i = 0; i < ndev; i++) {
if (devlist[I.sgfd >; 0) {
sts = set_sg_debug(devlist[I.sgfd, 0);
if (sts && fdebug)
fprintf(fdlog, "[%d] cant clear debug flag, sts=%d errno=%dn",
i, sts, errno);
close(devlist[I.sgfd); /*opened in beforedl() */
devlist[I.sgfd = 0;
}
}
return (sts);
} /*end afterdl() */

/* end sgdskfl.c */
在调用的时候,使用21号中断得到入口另外说明一点,GLIST是可以读取(0X37)清除(格式化)的,但是清楚以后故障还会存在。

再放一段程序便于你们理解。



int glist(SCSI *sp)
{
SCSI *s;
int al= 8, retval= -1, rv, format;
char format_mask[]= { 0x00, 0x04, 0x05, 0 };
int format_size[]= { 4,8,8,0 };

s= scsi_init(al);
idcpy(s, sp);

s->;s.scsi_command[0]= 0x37;
s->;s.scsi_command[2]= 0x08;
*(unsigned int *) &s->;s.scsi_command[7]= swapint(al);

for (rv= 0, format= 0; format < 3 && rv!= 1; format++)
{
s->;s.scsi_command[2]&= 0xf8;
s->;s.scsi_command[2]|= format_mask[format];
rv= scsi_execute(s, 0);
}
format--;

if (rv== 1)
{
retval= swapint(*(unsigned int *)&s->;s.data_buffer[2]) 
format_size[format];
}

scsi_destroy(s);
return(retval);
}

原创粉丝点击