Commit 8b255758 authored by John Ballance's avatar John Ballance
Browse files

Extend PartMan behaviour and add SWI and *command to list the detected...

Extend PartMan behaviour and add SWI and *command to list the detected partition start addresses and lengths. Improve interaction with SCSIFS.

Detail:
  Improved robustness. Made tolerant of some obstinate USB SD card
  readers that previously would cause the system to lock whilst the device
  was plugged in.
Admin:
  tested on iMx6

Version 0.14. Tagged as 'PartMan-0_14'
parent 25771e77
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "0.13"
Module_Version SETA 13
Module_MajorVersion SETS "0.14"
Module_Version SETA 14
Module_MinorVersion SETS ""
Module_Date SETS "09 Jan 2017"
Module_ApplicationDate SETS "09-Jan-17"
Module_Date SETS "13 Jul 2018"
Module_ApplicationDate SETS "13-Jul-18"
Module_ComponentName SETS "PartMan"
Module_ComponentPath SETS "castle/RiscOS/Sources/FileSys/SCSIFS/PartMan"
Module_FullVersion SETS "0.13"
Module_HelpVersion SETS "0.13 (09 Jan 2017)"
Module_FullVersion SETS "0.14"
Module_HelpVersion SETS "0.14 (13 Jul 2018)"
END
/* (0.13)
/* (0.14)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 0.13
#define Module_MajorVersion_CMHG 0.14
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 09 Jan 2017
#define Module_Date_CMHG 13 Jul 2018
#define Module_MajorVersion "0.13"
#define Module_Version 13
#define Module_MajorVersion "0.14"
#define Module_Version 14
#define Module_MinorVersion ""
#define Module_Date "09 Jan 2017"
#define Module_Date "13 Jul 2018"
#define Module_ApplicationDate "09-Jan-17"
#define Module_ApplicationDate "13-Jul-18"
#define Module_ComponentName "PartMan"
#define Module_ComponentPath "castle/RiscOS/Sources/FileSys/SCSIFS/PartMan"
#define Module_FullVersion "0.13"
#define Module_HelpVersion "0.13 (09 Jan 2017)"
#define Module_LibraryVersionInfo "0:13"
#define Module_FullVersion "0.14"
#define Module_HelpVersion "0.14 (13 Jul 2018)"
#define Module_LibraryVersionInfo "0:14"
......@@ -57,8 +57,11 @@ void testprint (char * fmt, ...)
FILE * fp;
va_list arg;
va_start (arg,fmt);
_kernel_swi_regs rr;
if((fp = fopen( debugfile,"ab")) != NULL)
{
_kernel_swi(OS_ReadMonotonicTime,&rr,&rr);
fprintf(fp," %d: ",rr.r[0]);
vfprintf(fp,fmt,arg);
fclose(fp);
}
......
......@@ -30,6 +30,7 @@ static PartitionRecord* partn;
static _kernel_oserror *err;
GUIDPartn * gpt=NULL;
static GUIDPartn * altgpt=NULL;
static _kernel_swi_regs rg;
static int DiscMaxLBA=0, DiscSectorSize=0;
......@@ -127,15 +128,39 @@ void freepointers(void)
//
bool CheckGPTValid(int device)
{
testprint("cgptv %d\n",device);
ReadDiscCapacity(device,OverrideKey,&DiscMaxLBA,&DiscSectorSize);
testprint("cgptv rdc done \n");
testprint(" dss><0 dev %d\n",device);
int timer;
static _kernel_oserror ee;
err=&ee;
testprint("Start cgptv id:%d\n",device);
_kernel_swi(OS_ReadMonotonicTime,&rg,&rg);
timer=rg.r[0]+75; // allow 75cs to get ready
err->errnum=ErrorNumber_SCSI_CC_NotReady;
err->errmess[0]=0;
while(err->errnum==ErrorNumber_SCSI_CC_NotReady)
{
err=ReadDiscCapacity(device,OverrideKey,&DiscMaxLBA,&DiscSectorSize);
testprint("cgptv rdc done1 err:%s\n",err?err->errmess:"");
_kernel_swi(OS_ReadMonotonicTime,&rg,&rg);
if(rg.r[0]>timer)
{
testprint("cgptv rdc done err:%s\n",err?err->errmess:"");
freepointers();return false;
}
}
testprint("cgptv rdc done err:%s\n",err?err->errmess:"");
if(DiscSectorSize==0){testprint(" dss=0 dev %d\n",device);return(false);}
testprint(" dss><0 dev %d\n",device);
testprint(" dss=%x dev %d\n",DiscSectorSize,device);
if(mbrp=calloc(1,sizeof(struct ProtectiveMBR)),mbrp)
{
#ifdef Debug
_kernel_swi(OS_ReadMonotonicTime,&rg,&rg);
testprint("before cgptv secrd time stamp %dcs\n", rg.r[0]);
#endif
err=SecRead(device,OverrideKey,mbrp,sizeof(struct ProtectiveMBR),0,DiscSectorSize);
#ifdef Debug
_kernel_swi(OS_ReadMonotonicTime,&rg,&rg);
testprint("time stamp %dcs\n", rg.r[0]);
#endif
if (!err)
{
partn=(PartitionRecord *)&mbrp->Partition1;
......@@ -232,6 +257,10 @@ bool CheckGPTValid(int device)
}
}
}
#ifdef Debug
_kernel_swi(OS_ReadMonotonicTime,&rg,&rg);
testprint("exit cgptv time stamp %dcs\n", rg.r[0]);
#endif
// return leaving all pointers in place
return true;
}
......@@ -335,7 +364,7 @@ int PartitionDisc(int device, int numpart, int partcount, int partn[])
int sectorsize;
int gptseccount,tmp;
// discover the device sector size and device size
ReadDiscCapacity(device, OverrideKey ,&capacity, &sectorsize);
err=ReadDiscCapacity(device, OverrideKey ,&capacity, &sectorsize);
if(capacity==0) {testprint("no disk there\n");return(-1);} // no disk there
// first claim space to work in
// use calloc() a we need to clear unused space
......
......@@ -24,7 +24,7 @@
#define task_name "gpttst" /* the name of our task */
static _kernel_swi_regs reg;
#define MaxPartitions 7
#define NumParts 3
#define NumParts 2
int main (int argc,char* argv[])
{
......
......@@ -28,12 +28,14 @@
#include "GPThdr.h"
#include "FormatBits.h"
#include "Format.h"
#include "SectorRW.h"
#include "Diagnostic.h"
void *module_wsp; // so we can know the module pwp globally
static int msg_struct[4];
static _kernel_oserror msg_buff;
static _kernel_swi_regs rg;
typedef struct partitionArray{
unsigned char used;
......@@ -47,16 +49,19 @@ typedef struct partitionArray{
typedef struct driveArray{
partitionArray partition[MaxPartitions];// at start of struct to alias address
int scsiid;
int initialised;
struct driveArray * next;
struct driveArray * last;
int mountcount;
struct driveArray * next; // drivArray following or NULL if last
struct driveArray * last; // driveArray preceeding, orNULL if first
}driveArray;
static driveArray *Drives;
driveArray * Drive2Array(int id);
driveArray * scsiID2Array(int id);
driveArray * scsiDisc2Array(int scsifsdisc);
void freeDriveArray(driveArray* array);
partitionArray * registerDrive(int id, int LBA);
driveArray* ReadDrivePartitions (int drive);
_kernel_oserror *PM_Sizes(_kernel_swi_regs *r, void *pw);
_kernel_oserror *PM_Reset(_kernel_swi_regs *r, void *pw);
#define task_name "Partition Manager" /* the name of our task */
......@@ -130,7 +135,6 @@ _kernel_oserror *module_initialise(const char *cmd_tail, int podule_base, void *
if(err = _swix(OS_Claim, _INR(0,2), UpCallV, upcallvhandler,
module_wsp), !err) UpCall = true;
callx_init(module_wsp);
return NULL;
faildereg:
......@@ -163,6 +167,7 @@ _kernel_oserror *module_finalise(int fatal, int podule, void *pw)
// remove any drive arrays
char buf[32];
testprint(" Dieing.. Drives:%p\n",Drives);
while (Drives)
{
// for each drive seen, dismount any reported discs and free memory
......@@ -170,10 +175,12 @@ _kernel_oserror *module_finalise(int fatal, int podule, void *pw)
Drives =(driveArray *)dr->next;
for (int i=0; i<MaxPartitions;i++)
{
testprint("mod die: dr:%p partn:%p drive%x used:%x mounted:%x\n",
dr,&(dr->partition[i]),dr->partition[i].drive,dr->partition[i].used,dr->partition[i].mounted);
sprintf(buf,"*scsi:dismount :%1d",dr->partition[i].drive);
if((dr->partition[i].used)&&(dr->partition[i].mounted))
{
// testprint(buf);
testprint("%s\n",buf);
_kernel_oscli(buf);
}
}
......@@ -188,31 +195,72 @@ _kernel_oserror *module_finalise(int fatal, int podule, void *pw)
_kernel_oserror *UpCallVHandler(_kernel_swi_regs *r, void *pw)
{
pw=pw;
if(r->r[0]==UpCall_DriveRemoved)
switch(r->r[0])
{
case UpCall_DriveRemoved:
{
testprint("UpCallDriveRemoved r0:%x r1:%x *r1:&x r2:%x r3:%x \n",r->r[0],r->r[1],*(int*)(r->r[1]),r->r[2],r->r[3]);
if(*(int*)(r->r[1]) == 0x49534353)
{
int drive = (int)*(char*)(r->r[1]+6) -0x30;
driveArray * dr = Drive2Array(drive);
if(dr) freeDriveArray(dr);
// testprint("removed %1d, ps:%x\n",drive,(int)dr);
driveArray * dr = scsiDisc2Array(drive);
testprint("UpCallV removing %d, dr:%p\n",drive,dr);
if(dr)
{
testprint("dr:%p mc this dr:%d\n",dr,dr->mountcount);
if(dr->mountcount<=1)
{
testprint("UpCallV1 removed and freed %d, dr:%p\n",drive,dr);
freeDriveArray(dr);
}
else
{
dr->mountcount--;
testprint("UpCallV2 removed %d, dr:%p mc:%d\n",drive,dr,dr->mountcount);
}
}
}
}
break;
case UpCall_DriveAdded:
{
testprint("UpCallDriveAdded r0:%x r1:%x *r1:%x r2:%x r3:%x \n",r->r[0],r->r[1],*(int*)(r->r[1]),r->r[2],r->r[3]);
}
break;
default: break;
}
return NULL;
}
// return drive array for this drive, or NULL
driveArray * Drive2Array(int id)
driveArray * scsiID2Array(int id)
{
driveArray * dr = Drives;
while(dr)
{
// testprint("d2a %x %x",id, (int)dr);
if((dr)->scsiid==id) break;
dr = ((dr)->next);
testprint("d2a dr:%p id:%x dr->id:%x\n", dr,id,dr->scsiid);
if(dr->scsiid==id) return dr;
dr = (dr->next);
}
return dr;
return NULL;
}
// return drive array for this scsifs disc
driveArray * scsiDisc2Array(int scsifsdisc)
{
driveArray * dr = Drives;
while(dr)
{
for(int i=0; i<=7; i++)
{
if(dr->partition[i].used && dr->partition[i].mounted && (dr->partition[i].drive==scsifsdisc)) return dr;
}
testprint("drive2a dr:%p id:%x mc:%x\n", dr,scsifsdisc,dr->mountcount);
dr = (dr->next);
}
return NULL;
}
// return next free partitionArray pointer for scsi ID
// or array relevant to this LBA
......@@ -220,23 +268,26 @@ driveArray * Drive2Array(int id)
// or null if all used,
partitionArray * registerDrive(int id, int LBA)
{
driveArray * dr = Drives, * newdrlast = dr;
// testprint("in rD %x Drives addr is %x\n",(int)dr,(int)&Drives);
driveArray * dr = Drives;
driveArray * newdrlast = dr;
testprint("in rD %x id %x Drives addr is %x\n",(int)dr,id,(int)&Drives);
while(dr)
{
if((dr)->scsiid==id) break;
if(dr->scsiid==id) break;
newdrlast = dr;
dr = ((dr)->next);
dr = (dr->next);
}
if(!dr)
{
testprint("rD need new drive array\n");
dr = (driveArray *)calloc(1,sizeof(driveArray));
if(dr)
{
(dr)->scsiid=id;
dr->scsiid=id;
testprint("rD id %x stored at %p in dr:%p\n",id,&(dr->scsiid),dr);
if(newdrlast)
{
(dr)->last = newdrlast;
dr->last = newdrlast;
dr->last->next=dr;
}
else
......@@ -244,18 +295,24 @@ partitionArray * registerDrive(int id, int LBA)
Drives=dr;
}
}
else
{ // allocation failure
return NULL;
}
}
// testprint(" Drives addr is %x ,pa addr %x recording %x as last\n",
// (int)&Drives,(int)(dr),(int)((dr)->last));
if(LBA==-1) return &(dr)->partition[0];
testprint("rD Drives:%p ,pa:%p, set:%p as last, id:%x stored at %p\n", Drives,dr,dr->last,dr->scsiid,&dr->scsiid);
if(LBA==-1) return &(dr->partition[0]);
for (int i=0;i<MaxPartitions;i++)
{
if ((!(dr)->partition[i].used)
|| ((dr)->partition[i].partitionLBA == LBA))
if ((!dr->partition[i].used)
|| (dr->partition[i].partitionLBA == LBA))
{
return &(dr)->partition[i];
testprint("rD returning actual pa=%p lba=%x\n",&(dr->partition[i]), dr->partition[i].partitionLBA);
return &(dr->partition[i]);
}
}
testprint("rD returning NULL\n");
return NULL;
}
......@@ -263,38 +320,46 @@ partitionArray * registerDrive(int id, int LBA)
void freeDriveArray(driveArray* array)
{
driveArray *temp = array;
bool irqs_were_off = _kernel_irqs_disabled();
if (!irqs_were_off) _kernel_irqs_off();
testprint("FDA array:%p \n",array);
if(array)
{
if((array)->last)
testprint("FDA last:%p next:%p\n",array->last,array->next);
if(array->last) // we're not the first array
{
if(array == Drives)
{
Drives=(array)->next;
if((array)->next)(array)->next->last=Drives;
array->last->next=array->next;
if(array->next)array->next->last=array->last;
}
else
{ // we're the first
if(array->next) // and something follows
{
(array)->last->next=(array)->next;
if((array)->next)(array)->next->last=(array)->last;
}
Drives = array->next;
array->next->last=NULL;
}
else
{
{ // ony one
Drives = NULL;
}
}
// testprint("free %x Drives = %x\n",(int)temp,(int)Drives);
if(temp)free(temp);
free(array);
testprint("FDA freed driveArray:%p\n",temp);
}
if (!irqs_were_off) _kernel_irqs_on();
}
// returns a driveArray* if partitions successfully found on drive
driveArray* ReadDrivePartitions (int drive)
{
driveArray* dr=Drive2Array(drive);
driveArray* dr=scsiID2Array(drive);
partitionArray* pa=registerDrive(drive, -1);
testprint("RDA dr %x\n", (int)dr);
testprint("RDA dr:%p pa:%p\n", dr,pa);
if (!pa->used)
{ // drive not evaluated yet.. get the partition table
testprint("about to cgptv %d\n",drive);
// first to inquiry on scsi ID (incl LUN)
if(CheckGPTValid(drive))
{ // found partition info
GUIDPartn* myGP;
......@@ -307,31 +372,51 @@ driveArray* ReadDrivePartitions (int drive)
if(GUIDValid((char*)(myGP->PTypeGUID)))
{
pa=registerDrive(drive, myGP->StartLBA[0]);
testprint("\npa found %x\n", (int)pa);
testprint("pa found %x\n", (int)pa);
if(pa)
{
pa->partitionLBA = myGP->StartLBA[0];
pa->used = 1;
pa->used = 2; testprint("1:used addr:%p pa:%p\n", &pa->used,pa);
}
testprint("Got drive start LBA %x, pa=%x\n",myGP->StartLBA[0],(int)pa);
}
myGP++;
}
if(!dr)dr=scsiID2Array(drive);
}
else
{ // couldnt get partition info
pa=registerDrive(drive, 0);
testprint("pa found %x\n", (int)pa);
if(pa)
{
pa->partitionLBA = 0;
pa->used = 2; testprint("1:used addr:%p pa:%p\n", &pa->used,pa);
}
testprint("Got drive start LBA %x, pa=%x\n",0,(int)pa);
testprint("\ncgptv failed.. reporting non partitioned\n");
return NULL;
}
}
testprint("rD returning %p\n",dr);
return dr;
}
_kernel_oserror* AttachCallBack (_kernel_swi_regs* r, void* pw, void* h)
static int inACB = 0;
static _kernel_oserror* AttachCallBack (_kernel_swi_regs* r, void* pw, void* h)
{
(void) r;
(void) pw;
testprint("ATTCA id %d\n",(int)h);
if(inACB)return NULL;
inACB=1;
testprint("AttachedCB id %d\n",(int)h);
ReadDrivePartitions((int)h);
rg.r[0]=(int)h;
rg.r[1]=PartMan_MorePartitions; // use swi number ..
rg.r[2]=0x1f;
_kernel_swi(OS_ServiceCall,&rg,&rg);
inACB=0;
return NULL;
}
......@@ -345,57 +430,30 @@ void module_service_handler(int service_number, _kernel_swi_regs *r, void *pw)
// attach and detach have device in r0 and mask in r2
case Service_SCSIAttached:
{
partitionArray * pa=registerDrive(r->r[0]&r->r[2], -1);
testprint("Attached id %x pa %x\n",r->r[0]&r->r[2],(int)pa);
// callx_add_callback(AttachCallBack,(void*)(r->r[0]&r->r[2]));
// ReadDrivePartitions(r->r[0]&r->r[2]);
// flag we have a new scsi ID
// testprint("attach scsi drive %x %x %x\n",r->r[0],r->r[2],r->r[0]&r->r[2]);
testprint("SvceSCSIAttached id=%02x mask=%02x\n",r->r[0],r->r[2]);
callx_add_callback(AttachCallBack,(void*)r->r[0]);
}
break;
case Service_SCSIDetached:
{
// testprint("detach drive %x %x %x\n",r->r[2],r->r[2],r->r[0]&r->r[2]);
// we need to forget the partition info for this drive
driveArray* dr = Drive2Array(r->r[0]&r->r[2]);
driveArray* dr = scsiID2Array(r->r[0]&r->r[2]);
testprint("abt to free %x\n",(int)dr);
if (dr) freeDriveArray(dr);
if(dr)
{
testprint("Detached id:%x mc:%d %s freeing dr:%p %s\n",r->r[0]&r->r[2],dr->mountcount,dr->mountcount?"not":"",dr,dr->mountcount?"till upcall":"");
if(!dr->mountcount) freeDriveArray(dr);
}
}
break;
case Service_SCSIMounting:
{ // r3 = scsi id
testprint("\nMounting %x %x %x %x \n",r->r[0],r->r[1],r->r[2],r->r[3]);
{ // r3 = scsi id, r2 = scsifs drive no
driveArray* dr=scsiID2Array(r->r[3]);
testprint("\nSCSIFS is mounting %x %x %x %x dr:%p\n",r->r[0],r->r[1],r->r[2],r->r[3],dr);
partitionArray* pa=&(ReadDrivePartitions (r->r[3]))->partition[0];
// Check in this drive, or get its table address
partitionArray* pa=&dr->partition[0];
testprint("pa found %p\n",pa);
partitionArray* pabase=pa;
// registerDrive(r->r[3], -1);
// testprint("basepa %x\n",(int)pa);
// if (!pa->used)
// { // drive not evaluated yet.. get the partition table
// if(CheckGPTValid(r->r[3]))
// {
// GUIDPartnp myGP;
// extern GUIDPartnp gpt; // set up by CheckGPTValid()
// extern GPTHeaderp gpth;
// myGP=gpt;
// for (int i=0; i<gpth->GUIDPnum;i++)
// {
// if(GUIDValid((char*)(myGP->PTypeGUID)))
// {
// pa=registerDrive(r->r[3], myGP->StartLBA[0]);
//// testprint("\npa found %x\n", (int)pa);
// if(pa)
// {
// pa->partitionLBA = myGP->StartLBA[0];
// pa->used = 1;
// }
// // testprint("Got drive start LBA %x, pa=%x\n",myGP->StartLBA[0],(int)pa);
// }
// myGP++;
// }
// }
// }
// now report next unused partition
if(pabase)
{
......@@ -403,17 +461,17 @@ void module_service_handler(int service_number, _kernel_swi_regs *r, void *pw)
{
if(pabase->used&&!pabase->mounted)
{
pabase->mounted=1;
pabase->mounted=4;
dr->mountcount++;
pabase->drive=r->r[2];
testprint("give partition offset for drive %d, ID %x as %x\n",r->r[2],r->r[3],pabase->partitionLBA);
_swix(SCSIFS_Partitions,_INR(0,2),0,r->r[2],pabase->partitionLBA);
i = MaxPartitions;
i = MaxPartitions+1;
}
pabase++;
if(i>=MaxPartitions)testprint("%s %x\n",(i==(MaxPartitions+1))?"One of ours.. offset ":"Not one of ours. ignored");
}
}
driveArray * dr;
if(dr = Drive2Array(r->r[3]), dr) dr->initialised = 1;
freepointers();
}
break;
......@@ -438,37 +496,94 @@ void module_service_handler(int service_number, _kernel_swi_regs *r, void *pw)
// and work out if further partitions possible
// On entry, r->r[1] = scsiID, r->r[2] =1
// On exit r->r[1] unchanged, r->r[2] = 0 if more partitions available
// if r->r[1] = -1 just exit no error (indicates module presence)
_kernel_oserror *PM_MorePartitions(_kernel_swi_regs *r, void *pw)
{
(void) pw;
driveArray* dr =Drive2Array(r->r[1]);
if(r->r[1]==-1) return (NULL);
driveArray* dr =scsiID2Array (r->r[1]);
testprint("PMMoreP id=%d dr= %p %d",r->r[1],dr,r->r[2]);
if(dr)
{ // this is a drive we've seen attached
testprint("PMM ");
dr = ReadDrivePartitions (r->r[1]);
if(dr)
{
partitionArray* pap=&dr->partition[0];
// if(!dr->initialised)
// {
// }
for (int i=0;i<MaxPartitions;i++)
{
if(pap->used&&!pap->reported)
if((pap->used)&&!(pap->reported))
{
pap->reported=1;
if((i<MaxPartitions-1)&&(++pap)&& (pap->used))r->r[2]=0;
testprint(":%02x pap %x \n",r->r[1],(int)pap);
pap->reported=8;
if((i<MaxPartitions-1)&&(++pap)&& (pap->used))
{ // check if more partitions
r->r[2]=0; // 0 if yes
}
testprint("end PMMorep reporting :%d\n",r->r[2]);
return NULL;
}
pap++;
}
testprint("Q\n");
}
testprint("end PMMoreP %d\n", r->r[2]);
return (NULL);
}
_kernel_oserror *PM_Reset(_kernel_swi_regs *r, void *pw)
{
(void)r;