Previous 199869 Revisions Next

r18344 Sunday 7th October, 2012 at 22:54:59 UTC by smf
Moved scsi protocol code from scsibus_device to scsihle_device, leaving scsibus_device to calculate the current bus contents and distribute it to each of the scsidev_device. [smf]
[src/emu/machine]scsibus.c scsibus.h scsicb.c scsicb.h scsidev.c scsidev.h scsihle.c scsihle.h

trunk/src/emu/machine/scsibus.c
r18343r18344
11/*
2    SCSIBus.c
32
4    Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI
5    controler chip such as the RM Nimbus, which implements it as a bunch of
6    74LS series chips.
3scsibus.c
74
85*/
96
107#include "emu.h"
11#include "machine/scsihle.h"
128#include "machine/scsibus.h"
13#include "debugger.h"
14#include "debug/debugcpu.h"
15#include "debug/debugcon.h"
169
17/*
18    LOGLEVEL
19        0   no logging,
20        1   just commands
21        2   1 + data
22        3   2 + line changes
23*/
24
25#define LOGLEVEL            0
26
27#define LOG(level,...)      if(LOGLEVEL>=level) logerror(__VA_ARGS__)
28
29static const char *const linenames[] =
10void scsibus_device::scsi_update()
3011{
31   "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset"
32};
12   UINT32 newdata = SCSI_MASK_ALL;
3313
34static const char *const phasenames[] =
35{
36   "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select"
37};
38
39void scsibus_device::dump_bytes(UINT8 *buff, int count)
40{
41   int byteno;
42
43   for(byteno=0; byteno<count; byteno++)
14   for( int i = 0; i < deviceCount; i++ )
4415   {
45      logerror("%02X ",buff[byteno]);
16      newdata &= devices[ i ]->data_out;
4617   }
47}
4818
49void scsibus_device::dump_command_bytes()
50{
51   logerror("sending command 0x%02X to ScsiID %d\n",command[0],last_id);
52   dump_bytes(command,cmd_idx);
53   logerror("\n\n");
54}
19   UINT32 mask = data ^ newdata;
5520
56void scsibus_device::dump_data_bytes(int count)
57{
58   logerror("Data buffer[0..%d]\n",count);
59   dump_bytes(buffer,count);
60   logerror("\n\n");
61}
62
63void scsibus_device::scsibus_read_data()
64{
65   data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left;
66
67   LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last);
68
69   if (data_last > 0)
21   if( mask != 0 )
7022   {
71      devices[last_id]->ReadData(buffer, data_last);
72      bytes_left-=data_last;
73   }
23      data = newdata;
7424
75   data_idx=0;
76}
77
78void scsibus_device::scsibus_write_data()
79{
80   if (data_last > 0)
81   {
82      devices[last_id]->WriteData(buffer, data_last);
83      bytes_left-=data_last;
84   }
85
86   data_idx=0;
87}
88
89/* SCSI Bus read/write */
90
91UINT8 scsibus_device::scsi_data_r()
92{
93   UINT8 result = 0;
94
95   switch (phase)
96   {
97      case SCSI_PHASE_DATAIN:
98         result=buffer[data_idx];
99         break;
100
101      case SCSI_PHASE_STATUS:
102         result=SCSI_STATUS_OK; // return command status
103         break;
104
105      case SCSI_PHASE_MESSAGE_IN:
106         result=0; // no errors for the time being !
107         break;
108   }
109
110   LOG(2,"scsi_data_r : %02x phase=%s, data_idx=%d, cmd_idx=%d\n",result,phasenames[phase],data_idx,cmd_idx);
111   return result;
112}
113
114void scsibus_device::scsi_data_w( UINT8 data )
115{
116   switch (phase)
117   {
118      // Note this assumes we only have one initiator and therefore
119      // only one line active.
120      case SCSI_PHASE_BUS_FREE:
121         last_id=scsibus_driveno(data);
122         sectorbytes = devices[last_id]->GetSectorBytes();
123         break;
124
125      case SCSI_PHASE_COMMAND:
126         command[cmd_idx]=data;
127         break;
128
129      case SCSI_PHASE_DATAOUT:
130
131         //LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx);
132
133         if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT))
134         {
135            // Only store the first 4 bytes of the bad block list (the header)
136            //if(data_idx<4)
137               buffer[data_idx]=data;
138               dump_data_bytes(4);
139            //else
140            //   data_idx++;
141
142            // If we have the first byte, then cancel the dataout timout
143            if(data_idx==0)
144               dataout_timer->adjust(attotime::never);
145
146            // When we have the first 3 bytes, calculate how many more are in the
147            // bad block list.
148            if(data_idx==2)
149            {
150               bytes_left+=((buffer[2]<<8)+buffer[3]);
151               LOG(1,"format_unit reading an extra %d bytes\n",bytes_left-4);
152               dump_data_bytes(4);
153            }
154         }
155         else
156         {
157            buffer[data_idx]=data;
158         }
159         break;
160   }
161}
162
163/* Get/Set lines */
164
165UINT8 scsibus_device::get_scsi_line(UINT8 lineno)
166{
167   UINT8 result=0;
168
169   switch (lineno)
170   {
171      case SCSI_LINE_BSY:   result=(linestate & (1<<SCSI_LINE_BSY)) >> SCSI_LINE_BSY; break;
172      case SCSI_LINE_SEL:   result=(linestate & (1<<SCSI_LINE_SEL)) >> SCSI_LINE_SEL; break;
173      case SCSI_LINE_CD:    result=(linestate & (1<<SCSI_LINE_CD )) >> SCSI_LINE_CD; break;
174      case SCSI_LINE_IO:    result=(linestate & (1<<SCSI_LINE_IO )) >> SCSI_LINE_IO; break;
175      case SCSI_LINE_MSG:   result=(linestate & (1<<SCSI_LINE_MSG)) >> SCSI_LINE_MSG; break;
176      case SCSI_LINE_REQ:   result=(linestate & (1<<SCSI_LINE_REQ)) >> SCSI_LINE_REQ; break;
177      case SCSI_LINE_ACK:   result=(linestate & (1<<SCSI_LINE_ACK)) >> SCSI_LINE_ACK; break;
178      case SCSI_LINE_ATN:   result=(linestate & (1<<SCSI_LINE_ATN)) >> SCSI_LINE_MSG; break;
179      case SCSI_LINE_RST:   result=(linestate & (1<<SCSI_LINE_RST)) >> SCSI_LINE_RST; break;
180   }
181
182   LOG(3,"get_scsi_line(%s)=%d\n",linenames[lineno],result);
183
184   return result;
185}
186
187void scsibus_device::set_scsi_line(UINT8 line, UINT8 state)
188{
189   UINT8 changed;
190
191   changed = ((linestate & (1<<line)) != (state << line));
192
193   LOG(3,"set_scsi_line(%s,%d), changed=%d, linestate=%02X\n",linenames[line],state,changed,linestate);
194
195   if(changed)
196   {
197      if (line==SCSI_LINE_ACK)
198         set_scsi_line_ack(state);
199      else
200         set_scsi_line_now(line,state);
201   }
202}
203
204void scsibus_device::set_scsi_line_now(UINT8 line, UINT8 state)
205{
206   if(state)
207      linestate |= (1<<line);
208   else
209      linestate &= ~(1<<line);
210
211   scsi_in_line_changed(line,state);
212}
213
214void scsibus_device::set_scsi_line_ack(UINT8 state)
215{
216   ack_timer->adjust(attotime::from_nsec(ACK_DELAY_NS),state);
217}
218
219void scsibus_device::scsibus_exec_command()
220{
221   int command_local = 0;
222   int newphase;
223
224   if(LOGLEVEL)
225      dump_command_bytes();
226
227   //is_linked=command[cmd_idx-1] & 0x01;
228   is_linked=0;
229
230   // Check for locally executed commands, and if found execute them
231   switch (command[0])
232   {
233      // Format unit
234      case SCSI_CMD_FORMAT_UNIT:
235         LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10));
236         command_local=1;
237         if((command[1] & 0x10)==0x10)
238            devices[last_id]->SetPhase(SCSI_PHASE_DATAOUT);
239         else
240            devices[last_id]->SetPhase(SCSI_PHASE_STATUS);
241
242         bytes_left=4;
243         dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT));
244         break;
245
246      case SCSI_CMD_SEARCH_DATA_EQUAL:
247         LOG(1,"SCSIBUS: Search_data_equaln");
248         command_local=1;
249         bytes_left=0;
250         devices[last_id]->SetPhase(SCSI_PHASE_STATUS);
251         break;
252
253      case SCSI_CMD_READ_DEFECT:
254         LOG(1,"SCSIBUS: read defect list\n");
255         command_local=1;
256
257         buffer[0] = 0x00;
258         buffer[1] = command[2];
259         buffer[3] = 0x00; // defect list len msb
260         buffer[4] = 0x00; // defect list len lsb
261
262         bytes_left=4;
263         devices[last_id]->SetPhase(SCSI_PHASE_DATAIN);
264         break;
265
266      // write buffer
267      case SCSI_CMD_BUFFER_WRITE:
268         LOG(1,"SCSIBUS: write_buffer\n");
269         command_local=1;
270         bytes_left=(command[7]<<8)+command[8];
271         devices[last_id]->SetPhase(SCSI_PHASE_DATAOUT);
272         break;
273
274      // read buffer
275      case SCSI_CMD_BUFFER_READ:
276         LOG(1,"SCSIBUS: read_buffer\n");
277         command_local=1;
278         bytes_left=(command[7]<<8)+command[8];
279         devices[last_id]->SetPhase(SCSI_PHASE_DATAIN);
280         break;
281   }
282
283
284   // Check for locally executed command, if not then pass it on
285   // to the disk driver
286   if(!command_local)
287   {
288      devices[last_id]->SetCommand(command, cmd_idx);
289      devices[last_id]->ExecCommand(&bytes_left);
290      data_idx=0;
291   }
292
293   devices[last_id]->GetPhase(&newphase);
294
295   scsi_change_phase(newphase);
296
297   LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx);
298
299   // This is correct as we need to read from disk for commands other than just read data
300   if ((phase == SCSI_PHASE_DATAIN) && (!command_local))
301      scsibus_read_data();
302}
303
304void scsibus_device::check_process_dataout()
305{
306   int capacity=0;
307   int tracks;
308   adaptec_sense_t *sense;
309
310   LOG(1,"SCSIBUS:check_process_dataout cmd=%02X\n",command[0]);
311
312   switch (command[0])
313   {
314      case SCSI_CMD_MODE_SELECT:
315         sense=(adaptec_sense_t *)buffer;
316         tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1];
317         capacity=(tracks * sense->head_count * 17);
318         LOG(1,"Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track);
319         LOG(1,"Setting disk capacity to %d blocks\n",capacity);
320         dump_data_bytes(0x16);
321         //debugger_break(device->machine());
322         break;
323   }
324}
325
326
327void scsibus_device::scsi_in_line_changed(UINT8 line, UINT8 state)
328{
329   void *hdfile;
330
331   // Reset aborts and returns to bus free
332   if((line==SCSI_LINE_RST) && (state==0))
333   {
334      scsi_change_phase(SCSI_PHASE_BUS_FREE);
335      cmd_idx=0;
336      data_idx=0;
337      is_linked=0;
338
339      return;
340   }
341
342   switch (phase)
343   {
344      case SCSI_PHASE_BUS_FREE:
345         if((line==SCSI_LINE_SEL) && (devices[last_id]!=NULL))
346         {
347            // Check to see if device had image file mounted, if not, do not set busy,
348            // and stay busfree.
349            devices[last_id]->GetDevice(&hdfile);
350            if(hdfile!=(void *)NULL)
351            {
352               if(state==0)
353                  sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS));
354               else
355                  scsi_change_phase(SCSI_PHASE_COMMAND);
356            }
357         }
358         break;
359
360      case SCSI_PHASE_COMMAND:
361         if(line==SCSI_LINE_ACK)
362         {
363            if(state)
364            {
365               cmd_idx++;
366
367               // If the command is ready go and execute it
368               if(cmd_idx==get_scsi_cmd_len(command[0]))
369               {
370                  scsibus_exec_command();
371               }
372               else
373                  scsi_out_line_change(SCSI_LINE_REQ,0);
374            }
375            else
376               scsi_out_line_change(SCSI_LINE_REQ,1);
377         }
378         break;
379
380      case SCSI_PHASE_DATAIN:
381         if(line==SCSI_LINE_ACK)
382         {
383            if(state)
384            {
385               data_idx++;
386
387               // check to see if we have reached the end of the block buffer
388               // and that there is more data to read from the scsi disk
389               if(data_idx==sectorbytes)
390               {
391                  scsibus_read_data();
392               }
393
394               if(data_idx == data_last && bytes_left == 0)
395                  scsi_change_phase(SCSI_PHASE_STATUS);
396               else
397                  scsi_out_line_change(SCSI_LINE_REQ,0);
398            }
399            else
400               scsi_out_line_change(SCSI_LINE_REQ,1);
401         }
402         break;
403
404      case SCSI_PHASE_DATAOUT:
405         if(line==SCSI_LINE_ACK)
406         {
407            if(state)
408            {
409               data_idx++;
410
411               // If the data buffer is full flush it to the SCSI disk
412
413               data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left;
414
415               if(data_idx == data_last)
416                  scsibus_write_data();
417
418               if(data_idx == 0 && bytes_left == 0)
419               {
420                  check_process_dataout();
421                  scsi_change_phase(SCSI_PHASE_STATUS);
422               }
423               else
424                  scsi_out_line_change(SCSI_LINE_REQ,0);
425            }
426            else
427               scsi_out_line_change(SCSI_LINE_REQ,1);
428         }
429         break;
430
431      case SCSI_PHASE_STATUS:
432         if(line==SCSI_LINE_ACK)
433         {
434            if(state)
435            {
436               if(cmd_idx > 0)
437               {
438                  scsi_change_phase(SCSI_PHASE_MESSAGE_IN);
439               }
440               else
441                  scsi_out_line_change(SCSI_LINE_REQ,0);
442            }
443            else
444            {
445               cmd_idx++;
446               scsi_out_line_change(SCSI_LINE_REQ,1);
447            }
448         }
449         break;
450
451      case SCSI_PHASE_MESSAGE_IN:
452         if(line==SCSI_LINE_ACK)
453         {
454            if(state)
455            {
456               if(cmd_idx > 0)
457               {
458                  if(is_linked)
459                     scsi_change_phase(SCSI_PHASE_COMMAND);
460                  else
461                     scsi_change_phase(SCSI_PHASE_BUS_FREE);
462               }
463               else
464                  scsi_out_line_change(SCSI_LINE_REQ,0);
465            }
466            else
467            {
468               cmd_idx++;
469               scsi_out_line_change(SCSI_LINE_REQ,1);
470            }
471         }
472         break;
473   }
474}
475
476void scsibus_device::scsi_out_line_change(UINT8 line, UINT8 state)
477{
478   if(line==SCSI_LINE_REQ)
479      scsi_out_line_req(state);
480   else
481      scsi_out_line_change_now(line,state);
482}
483
484void scsibus_device::scsi_out_line_change_now(UINT8 line, UINT8 state)
485{
486   if(state)
487      linestate |= (1<<line);
488   else
489      linestate &= ~(1<<line);
490
491   LOG(3,"scsi_out_line_change(%s,%d)\n",linenames[line],state);
492
493   if(m_scsicb != NULL)
494   {
495      switch (line)
25      for( int i = 0; i < deviceCount; i++ )
49626      {
497      case SCSI_LINE_BSY: m_scsicb->out_bsy_func(state); break;
498      case SCSI_LINE_SEL: m_scsicb->out_sel_func(state); break;
499      case SCSI_LINE_CD: m_scsicb->out_cd_func(state); break;
500      case SCSI_LINE_IO: m_scsicb->out_io_func(state); break;
501      case SCSI_LINE_MSG: m_scsicb->out_msg_func(state); break;
502      case SCSI_LINE_REQ: m_scsicb->out_req_func(state); break;
503      case SCSI_LINE_ACK: m_scsicb->out_ack_func(state); break;
504      case SCSI_LINE_ATN: m_scsicb->out_atn_func(state); break;
505      case SCSI_LINE_RST: m_scsicb->out_rst_func(state); break;
27         devices[ i ]->scsi_in( data, mask );
50628      }
50729   }
50830}
50931
510void scsibus_device::scsi_out_line_req(UINT8 state)
511{
512   req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state);
513}
514
515void scsibus_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
516{
517   switch( tid )
518   {
519   case 0:
520      scsi_out_line_change_now(SCSI_LINE_REQ, param);
521      break;
522
523   case 1:
524      set_scsi_line_now(SCSI_LINE_ACK, param);
525      break;
526
527   case 2:
528      scsi_out_line_change_now(SCSI_LINE_BSY, param);
529      break;
530
531   case 3:
532      // Some drives, notably the ST225N and ST125N, accept fromat unit commands
533      // with flags set indicating that bad block data should be transfered but
534      // don't then implemnt a data in phase, this timeout it to catch these !
535      if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT) && (data_idx==0))
536         scsi_change_phase(SCSI_PHASE_STATUS);
537      break;
538   }
539}
540
541void scsibus_device::scsi_change_phase(UINT8 newphase)
542{
543   LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[phase],phasenames[newphase]);
544
545   phase=newphase;
546   cmd_idx=0;
547   data_idx=0;
548
549   switch(phase)
550   {
551      case SCSI_PHASE_BUS_FREE:
552         scsi_out_line_change(SCSI_LINE_CD,1);
553         scsi_out_line_change(SCSI_LINE_IO,1);
554         scsi_out_line_change(SCSI_LINE_MSG,1);
555         scsi_out_line_change(SCSI_LINE_REQ,1);
556         scsi_out_line_change(SCSI_LINE_BSY,1);
557         LOG(1,"SCSIBUS: done\n\n");
558         break;
559
560      case SCSI_PHASE_COMMAND:
561         scsi_out_line_change(SCSI_LINE_CD,0);
562         scsi_out_line_change(SCSI_LINE_IO,1);
563         scsi_out_line_change(SCSI_LINE_MSG,1);
564         scsi_out_line_change(SCSI_LINE_REQ,0);
565         LOG(1,"\nSCSIBUS: Command begin\n");
566         break;
567
568      case SCSI_PHASE_DATAOUT:
569         scsi_out_line_change(SCSI_LINE_CD,1);
570         scsi_out_line_change(SCSI_LINE_IO,1);
571         scsi_out_line_change(SCSI_LINE_MSG,1);
572         scsi_out_line_change(SCSI_LINE_REQ,0);
573         break;
574
575      case SCSI_PHASE_DATAIN:
576         scsi_out_line_change(SCSI_LINE_CD,1);
577         scsi_out_line_change(SCSI_LINE_IO,0);
578         scsi_out_line_change(SCSI_LINE_MSG,1);
579         scsi_out_line_change(SCSI_LINE_REQ,0);
580         break;
581
582      case SCSI_PHASE_STATUS:
583         scsi_out_line_change(SCSI_LINE_CD,0);
584         scsi_out_line_change(SCSI_LINE_IO,0);
585         scsi_out_line_change(SCSI_LINE_MSG,1);
586         scsi_out_line_change(SCSI_LINE_REQ,0);
587         break;
588
589      case SCSI_PHASE_MESSAGE_OUT:
590         scsi_out_line_change(SCSI_LINE_CD,0);
591         scsi_out_line_change(SCSI_LINE_IO,1);
592         scsi_out_line_change(SCSI_LINE_MSG,0);
593         scsi_out_line_change(SCSI_LINE_REQ,0);
594         break;
595
596      case SCSI_PHASE_MESSAGE_IN:
597         scsi_out_line_change(SCSI_LINE_CD,0);
598         scsi_out_line_change(SCSI_LINE_IO,0);
599         scsi_out_line_change(SCSI_LINE_MSG,0);
600         scsi_out_line_change(SCSI_LINE_REQ,0);
601         break;
602   }
603}
604
605UINT8 scsibus_device::scsibus_driveno(UINT8 drivesel)
606{
607   switch (drivesel)
608   {
609      case 0x01: return 0;
610      case 0x02: return 1;
611      case 0x04: return 2;
612      case 0x08: return 3;
613      case 0x10: return 4;
614      case 0x20: return 5;
615      case 0x40: return 6;
616      case 0x80: return 7;
617      default: return 0;
618   }
619}
620
621// get the length of a SCSI command based on it's command byte type
622int scsibus_device::get_scsi_cmd_len(int cbyte)
623{
624   int group;
625
626   group = (cbyte>>5) & 7;
627
628   if (group == 0 || group == 3 || group == 6 || group == 7) return 6;
629   if (group == 1 || group == 2) return 10;
630   if (group == 5) return 12;
631
632   fatalerror("scsibus: Unknown SCSI command group %d, command byte=%02X\n", group,cbyte);
633
634   return 6;
635}
636
63732scsibus_device::scsibus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
63833    : device_t(mconfig, SCSIBUS, "SCSI bus", tag, owner, clock)
63934{
r18343r18344
64136
64237void scsibus_device::device_start()
64338{
644   memset(devices, 0, sizeof(devices));
39   deviceCount = 0;
64540
646   // All lines start high - inactive
647   linestate=0xFF;
648
649   // Start with bus free
650   phase=SCSI_PHASE_BUS_FREE;
651
652   // Setup req/ack/sel timers
653   req_timer=timer_alloc(0);
654   ack_timer=timer_alloc(1);
655   sel_timer=timer_alloc(2);
656   dataout_timer=timer_alloc(3);
657
65841   for( device_t *device = first_subdevice(); device != NULL; device = device->next() )
65942   {
660      scsihle_device *scsidev = dynamic_cast<scsihle_device *>(device);
43      scsidev_device *scsidev = dynamic_cast<scsidev_device *>(device);
66144      if( scsidev != NULL )
66245      {
663         devices[scsidev->GetDeviceID()] = scsidev;
46         devices[ deviceCount++ ] = scsidev;
66447      }
665      else
666      {
667         scsicb_device *scsicb = dynamic_cast<scsicb_device *>(device);
668         m_scsicb = scsicb;
669      }
67048   }
49
50   data = SCSI_MASK_ALL;
67151}
67252
67353const device_type SCSIBUS = &device_creator<scsibus_device>;
trunk/src/emu/machine/scsibus.h
r18343r18344
11/*
2    SCSIBus.h
32
3scsibus.h
4
45*/
56
67#pragma once
r18343r18344
89#ifndef _SCSIBUS_H_
910#define _SCSIBUS_H_
1011
11#include "machine/scsicb.h"
12#include "machine/scsihle.h"
12#include "machine/scsidev.h"
1313
14
15/***************************************************************************
16    MACROS
17***************************************************************************/
18
19#define MCFG_SCSIBUS_ADD(_tag) \
20   MCFG_DEVICE_ADD(_tag, SCSIBUS, 0)
21
22
23/***************************************************************************
24    CONSTANTS
25***************************************************************************/
26
27#define SCSI_LINE_BSY   0
28#define SCSI_LINE_SEL   1
29#define SCSI_LINE_CD    2
30#define SCSI_LINE_IO    3
31#define SCSI_LINE_MSG   4
32#define SCSI_LINE_REQ   5
33#define SCSI_LINE_ACK   6
34#define SCSI_LINE_ATN   7
35#define SCSI_LINE_RST   8
36
37#define REQ_DELAY_NS    90
38#define ACK_DELAY_NS    90
39#define BSY_DELAY_NS   50
40
41#define CMD_BUF_SIZE             32
42#define ADAPTEC_BUF_SIZE         1024
43
44// scsidev
45#define SCSI_CMD_BUFFER_WRITE ( 0x3b )
46#define SCSI_CMD_BUFFER_READ ( 0x3c )
47
48// scsihd
49#define SCSI_CMD_FORMAT_UNIT       0x04
50#define SCSI_CMD_SEARCH_DATA_EQUAL   0x31
51#define SCSI_CMD_READ_DEFECT       0x37
52
53
54#define IS_COMMAND(cmd)            (command[0]==cmd)
55#define IS_READ_COMMAND()          ((command[0]==0x08) || (command[0]==0x28) || (command[0]==0xa8))
56#define IS_WRITE_COMMAND()         ((command[0]==0x0a) || (command[0]==0x2a))
57
58#define FORMAT_UNIT_TIMEOUT         5
59
60struct adaptec_sense_t
61{
62   // parameter list
63   UINT8      reserved1[3];
64   UINT8      length;
65
66   // descriptor list
67   UINT8      density;
68   UINT8      reserved2[4];
69   UINT8      block_size[3];
70
71   // drive parameter list
72   UINT8      format_code;
73   UINT8      cylinder_count[2];
74   UINT8      head_count;
75   UINT8      reduced_write[2];
76   UINT8      write_precomp[2];
77   UINT8      landing_zone;
78   UINT8      step_pulse_code;
79   UINT8      bit_flags;
80   UINT8      sectors_per_track;
81};
82
8314class scsibus_device : public device_t
8415{
8516public:
r18343r18344
8718   scsibus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
8819   /* SCSI Bus read/write */
8920
90   UINT8 scsi_data_r();
91   void scsi_data_w( UINT8 data );
21   void scsi_update();
9222
93   /* Get/Set lines */
94
95   UINT8 get_scsi_line(UINT8 lineno);
96   void set_scsi_line(UINT8 line, UINT8 state);
97
9823protected:
9924   // device-level overrides
10025   virtual void device_start();
101   virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
10226
10327private:
104   int get_scsi_cmd_len(int cbyte);
105   UINT8 scsibus_driveno(UINT8  drivesel);
106   void scsi_change_phase(UINT8 newphase);
107   void set_scsi_line_now(UINT8 line, UINT8 state);
108   void set_scsi_line_ack(UINT8 state);
109   void scsi_in_line_changed(UINT8 line, UINT8 state);
110   void scsi_out_line_change(UINT8 line, UINT8 state);
111   void scsi_out_line_change_now(UINT8 line, UINT8 state);
112   void scsi_out_line_req(UINT8 state);
113   void scsibus_read_data();
114   void scsibus_write_data();
115   void scsibus_exec_command();
116   void check_process_dataout();
117   void dump_command_bytes();
118   void dump_data_bytes(int count);
119   void dump_bytes(UINT8 *buff, int count);
28   scsidev_device *devices[16];
12029
121   scsihle_device          *devices[8];
122   scsicb_device *m_scsicb;
123
124   UINT8       linestate;
125   UINT8       last_id;
126   UINT8       phase;
127
128   UINT8       command[CMD_BUF_SIZE];
129   UINT8       cmd_idx;
130   UINT8       is_linked;
131
132   UINT8       buffer[ADAPTEC_BUF_SIZE];
133   UINT16      data_idx;
134   int         bytes_left;
135   int         data_last;
136   int         sectorbytes;
137
138   emu_timer *req_timer;
139   emu_timer *ack_timer;
140   emu_timer *sel_timer;
141   emu_timer *dataout_timer;
30   UINT32 data;
31   int deviceCount;
14232};
14333
34#define MCFG_SCSIBUS_ADD(_tag) \
35   MCFG_DEVICE_ADD(_tag, SCSIBUS, 0)
36
14437// device type definition
14538extern const device_type SCSIBUS;
14639
trunk/src/emu/machine/scsihle.c
r18343r18344
1/***************************************************************************
1/*
22
3 scsihle.c - Base class for HLE'd SCSI devices.
3scsihle.c
44
5***************************************************************************/
5Base class for HLE'd SCSI devices.
66
7#include "emu.h"
7*/
8
89#include "machine/scsihle.h"
910
1011scsihle_device::scsihle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
r18343r18344
1415
1516void scsihle_device::device_start()
1617{
18   scsidev_device::device_start();
19
20   //req_timer = timer_alloc(0);
21   //ack_timer = timer_alloc(1);
22   sel_timer = timer_alloc(2);
23   dataout_timer = timer_alloc(3);
24
1725   save_item( NAME( command ) );
1826   save_item( NAME( commandLength ) );
1927   save_item( NAME( phase ) );
28
29   // Start with bus free
30   phase = SCSI_PHASE_BUS_FREE;
2031}
2132
2233#define SCSI_SENSE_SIZE            4
r18343r18344
128139   return scsiID;
129140}
130141
131int scsihle_device::GetSectorBytes()
132{
133   return 0;
134}
135
136142void scsihle_device::static_set_deviceid( device_t &device, int _scsiID )
137143{
138144   scsihle_device &scsidev = downcast<scsihle_device &>(device);
r18343r18344
153159{
154160   return ( *(length) << 8 ) | *(length + 1 );
155161}
162
163#define BSY_DELAY_NS    50
164//#define REQ_DELAY_NS    90
165//#define ACK_DELAY_NS    90
166
167static const char *const phasenames[] =
168{
169   "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select"
170};
171
172// scsidev
173#define SCSI_CMD_BUFFER_WRITE ( 0x3b )
174#define SCSI_CMD_BUFFER_READ ( 0x3c )
175
176// scsihd
177#define SCSI_CMD_FORMAT_UNIT       0x04
178#define SCSI_CMD_SEARCH_DATA_EQUAL   0x31
179#define SCSI_CMD_READ_DEFECT       0x37
180
181
182#define IS_COMMAND(cmd)            (command[0]==cmd)
183#define IS_READ_COMMAND()          ((command[0]==0x08) || (command[0]==0x28) || (command[0]==0xa8))
184#define IS_WRITE_COMMAND()         ((command[0]==0x0a) || (command[0]==0x2a))
185
186#define FORMAT_UNIT_TIMEOUT         5
187
188struct adaptec_sense_t
189{
190   // parameter list
191   UINT8      reserved1[3];
192   UINT8      length;
193
194   // descriptor list
195   UINT8      density;
196   UINT8      reserved2[4];
197   UINT8      block_size[3];
198
199   // drive parameter list
200   UINT8      format_code;
201   UINT8      cylinder_count[2];
202   UINT8      head_count;
203   UINT8      reduced_write[2];
204   UINT8      write_precomp[2];
205   UINT8      landing_zone;
206   UINT8      step_pulse_code;
207   UINT8      bit_flags;
208   UINT8      sectors_per_track;
209};
210
211/*
212    LOGLEVEL
213        0   no logging,
214        1   just commands
215        2   1 + data
216        3   2 + line changes
217*/
218
219#define LOGLEVEL            0
220
221#define LOG(level,...)      if(LOGLEVEL>=level) logerror(__VA_ARGS__)
222
223//static const char *const linenames[] =
224//{
225//   "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset"
226//};
227
228//void scsibus_device::set_scsi_line(UINT8 line, UINT8 state)
229//{
230//   UINT8 changed = linestate[line] != state;
231//
232//   LOG(3,"set_scsi_line(%s,%d), changed=%d\n",linenames[line],state,changed);
233//
234//   if(changed)
235//   {
236//      if (line==SCSI_LINE_ACK)
237//         set_scsi_line_ack(state);
238//      else
239//         set_scsi_line_now(line,state);
240//   }
241//}
242//
243//void scsibus_device::set_scsi_line_now( UINT8 line, UINT8 state )
244//{
245//   if( linestate[ line ] != state )
246//   {
247//      linestate[ line ] = state;
248//
249//      for( int i = 0; i < deviceCount; i++ )
250//      {
251//         devices[ i ]->scsi_in_line_changed( line, state );
252//      }
253//   }
254//}
255//
256//void scsibus_device::set_scsi_line_ack(UINT8 state)
257//{
258//   ack_timer->adjust(attotime::from_nsec(ACK_DELAY_NS),state);
259//}
260//
261//void scsibus_device::scsi_out_line_change(UINT8 line, UINT8 state)
262//{
263//   if(line==SCSI_LINE_REQ)
264//      scsi_out_line_req(state);
265//   else
266//      scsi_out_line_change_now(line,state);
267//}
268//
269//void scsibus_device::scsi_out_line_change_now(UINT8 line, UINT8 state)
270//{
271//   if( linestate[ line ] != state )
272//   {
273//      linestate[ line ] = state;
274//
275//      LOG(3,"scsi_out_line_change(%s,%d)\n",linenames[line],state);
276//   }
277//}
278//
279//void scsibus_device::scsi_out_line_req(UINT8 state)
280//{
281//   req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state);
282//}
283//
284
285void scsihle_device::dump_bytes(UINT8 *buff, int count)
286{
287   int byteno;
288
289   for(byteno=0; byteno<count; byteno++)
290   {
291      logerror("%02X ",buff[byteno]);
292   }
293}
294
295void scsihle_device::dump_command_bytes()
296{
297   logerror("sending command 0x%02X to ScsiID %d\n",command[0],scsiID);
298   dump_bytes(command,cmd_idx);
299   logerror("\n\n");
300}
301
302void scsihle_device::dump_data_bytes(int count)
303{
304   logerror("Data buffer[0..%d]\n",count);
305   dump_bytes(buffer,count);
306   logerror("\n\n");
307}
308
309void scsihle_device::scsibus_read_data()
310{
311   data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left;
312
313   LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last);
314
315   data_idx=0;
316
317   if (data_last > 0)
318   {
319      ReadData(buffer, data_last);
320      bytes_left-=data_last;
321
322      scsi_out( buffer[ data_idx++ ], SCSI_MASK_DATA );
323   }
324}
325
326void scsihle_device::scsibus_write_data()
327{
328   if (data_last > 0)
329   {
330      WriteData(buffer, data_last);
331      bytes_left-=data_last;
332   }
333
334   data_idx=0;
335}
336
337void scsihle_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
338{
339   switch( tid )
340   {
341//   case 0:
342//      scsi_out_line_change_now(SCSI_LINE_REQ, param);
343//      break;
344//
345//   case 1:
346//      set_scsi_line_now(SCSI_LINE_ACK, param);
347//      break;
348
349   case 2:
350      scsi_out(param * SCSI_MASK_BSY, SCSI_MASK_BSY);
351      break;
352
353   case 3:
354      // Some drives, notably the ST225N and ST125N, accept fromat unit commands
355      // with flags set indicating that bad block data should be transfered but
356      // don't then implemnt a data in phase, this timeout it to catch these !
357      if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT) && (data_idx==0))
358         scsi_change_phase(SCSI_PHASE_STATUS);
359      break;
360   }
361}
362
363void scsihle_device::scsibus_exec_command()
364{
365   int command_local = 0;
366   int newphase;
367
368   if(LOGLEVEL)
369      dump_command_bytes();
370
371   //is_linked=command[cmd_idx-1] & 0x01;
372   is_linked=0;
373
374   // Check for locally executed commands, and if found execute them
375   switch (command[0])
376   {
377      // Format unit
378      case SCSI_CMD_FORMAT_UNIT:
379         LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10));
380         command_local=1;
381         if((command[1] & 0x10)==0x10)
382            SetPhase(SCSI_PHASE_DATAOUT);
383         else
384            SetPhase(SCSI_PHASE_STATUS);
385
386         bytes_left=4;
387         dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT));
388         break;
389
390      case SCSI_CMD_SEARCH_DATA_EQUAL:
391         LOG(1,"SCSIBUS: Search_data_equaln");
392         command_local=1;
393         bytes_left=0;
394         SetPhase(SCSI_PHASE_STATUS);
395         break;
396
397      case SCSI_CMD_READ_DEFECT:
398         LOG(1,"SCSIBUS: read defect list\n");
399         command_local=1;
400
401         buffer[0] = 0x00;
402         buffer[1] = command[2];
403         buffer[3] = 0x00; // defect list len msb
404         buffer[4] = 0x00; // defect list len lsb
405
406         bytes_left=4;
407         SetPhase(SCSI_PHASE_DATAIN);
408         break;
409
410      // write buffer
411      case SCSI_CMD_BUFFER_WRITE:
412         LOG(1,"SCSIBUS: write_buffer\n");
413         command_local=1;
414         bytes_left=(command[7]<<8)+command[8];
415         SetPhase(SCSI_PHASE_DATAOUT);
416         break;
417
418      // read buffer
419      case SCSI_CMD_BUFFER_READ:
420         LOG(1,"SCSIBUS: read_buffer\n");
421         command_local=1;
422         bytes_left=(command[7]<<8)+command[8];
423         SetPhase(SCSI_PHASE_DATAIN);
424         break;
425   }
426
427
428   // Check for locally executed command, if not then pass it on
429   // to the disk driver
430   if(!command_local)
431   {
432      SetCommand(command, cmd_idx);
433      ExecCommand(&bytes_left);
434      data_idx=0;
435   }
436
437   GetPhase(&newphase);
438
439   scsi_change_phase(newphase);
440
441   LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx);
442
443   // This is correct as we need to read from disk for commands other than just read data
444   if ((phase == SCSI_PHASE_DATAIN) && (!command_local))
445      scsibus_read_data();
446}
447
448UINT8 scsihle_device::scsibus_driveno(UINT8 drivesel)
449{
450   switch (drivesel)
451   {
452      case 0x01: return 0;
453      case 0x02: return 1;
454      case 0x04: return 2;
455      case 0x08: return 3;
456      case 0x10: return 4;
457      case 0x20: return 5;
458      case 0x40: return 6;
459      case 0x80: return 7;
460      default: return 0;
461   }
462}
463
464void scsihle_device::scsi_change_phase(UINT8 newphase)
465{
466   LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[phase],phasenames[newphase]);
467
468   phase=newphase;
469   cmd_idx=0;
470   data_idx=0;
471
472   switch(phase)
473   {
474      case SCSI_PHASE_BUS_FREE:
475         scsi_out( SCSI_MASK_ALL, SCSI_MASK_ALL );
476         LOG(1,"SCSIBUS: done\n\n");
477         break;
478
479      case SCSI_PHASE_COMMAND:
480         scsi_out( SCSI_MASK_DATA | SCSI_MASK_IO | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );
481         LOG(1,"\nSCSIBUS: Command begin\n");
482         break;
483
484      case SCSI_PHASE_DATAOUT:
485         scsi_out( SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG, SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );
486         break;
487
488      case SCSI_PHASE_DATAIN:
489         scsi_out( SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );
490         break;
491
492      case SCSI_PHASE_STATUS:
493         scsi_out( SCSI_STATUS_OK | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );
494         break;
495
496      case SCSI_PHASE_MESSAGE_OUT:
497         scsi_out( SCSI_MASK_IO, SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );
498         break;
499
500      case SCSI_PHASE_MESSAGE_IN:
501         scsi_out( 0, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );// no errors for the time being !
502         break;
503   }
504}
505
506void scsihle_device::scsi_in( UINT32 data, UINT32 mask )
507{
508   // Reset aborts and returns to bus free
509   if( ( mask & SCSI_MASK_RST ) != 0 && ( data & SCSI_MASK_RST ) == 0 )
510   {
511      scsi_change_phase(SCSI_PHASE_BUS_FREE);
512      cmd_idx=0;
513      data_idx=0;
514      is_linked=0;
515
516      return;
517   }
518
519   switch (phase)
520   {
521      case SCSI_PHASE_BUS_FREE:
522         // Note this assumes we only have one initiator and therefore
523         // only one line active.
524         if( ( mask & SCSI_MASK_SEL ) != 0 && scsibus_driveno(data & SCSI_MASK_DATA) == scsiID)
525         {
526            void *hdfile;
527            // Check to see if device had image file mounted, if not, do not set busy,
528            // and stay busfree.
529            GetDevice(&hdfile);
530            if(hdfile!=(void *)NULL)
531            {
532               if( ( data & SCSI_MASK_SEL ) != 0 )
533               {
534                  sectorbytes = GetSectorBytes();
535                  scsi_change_phase(SCSI_PHASE_COMMAND);
536               }
537               else
538               {
539                  sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS));
540               }
541            }
542         }
543         break;
544
545      case SCSI_PHASE_COMMAND:
546         if( ( mask & SCSI_MASK_ACK ) != 0 )
547         {
548            if( ( data & SCSI_MASK_ACK ) != 0 )
549            {
550               command[ cmd_idx++ ] = data & SCSI_MASK_DATA;
551
552               // If the command is ready go and execute it
553               if(cmd_idx==get_scsi_cmd_len(command[0]))
554               {
555                  scsibus_exec_command();
556               }
557               else
558               {
559                  scsi_out( 0, SCSI_MASK_REQ );
560               }
561            }
562            else
563            {
564               scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ );
565            }
566         }
567         break;
568
569      case SCSI_PHASE_DATAIN:
570         if( ( mask & SCSI_MASK_ACK ) != 0 )
571         {
572            if( ( data & SCSI_MASK_ACK ) != 0 )
573            {
574               // check to see if we have reached the end of the block buffer
575               // and that there is more data to read from the scsi disk
576               if(data_idx==sectorbytes)
577               {
578                  scsibus_read_data();
579               }
580
581               if(data_idx == data_last && bytes_left == 0)
582               {
583                  scsi_change_phase(SCSI_PHASE_STATUS);
584               }
585               else
586               {
587                  scsi_out( buffer[ data_idx++ ], SCSI_MASK_DATA | SCSI_MASK_REQ );
588               }
589            }
590            else
591            {
592               scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ );
593            }
594         }
595         break;
596
597      case SCSI_PHASE_DATAOUT:
598         if( ( mask & SCSI_MASK_ACK ) != 0 )
599         {
600            if( ( data & SCSI_MASK_ACK ) != 0 )
601            {
602               //LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx);
603               buffer[data_idx++]=data & SCSI_MASK_DATA;
604
605               if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT))
606               {
607                  // If we have the first byte, then cancel the dataout timout
608                  if(data_idx==1)
609                     dataout_timer->adjust(attotime::never);
610
611                  // When we have the first 3 bytes, calculate how many more are in the
612                  // bad block list.
613                  if(data_idx==3)
614                  {
615                     bytes_left+=((buffer[2]<<8)+buffer[3]);
616                     LOG(1,"format_unit reading an extra %d bytes\n",bytes_left-4);
617                     dump_data_bytes(4);
618                  }
619               }
620               
621               // If the data buffer is full flush it to the SCSI disk
622
623               data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left;
624
625               if(data_idx == data_last)
626                  scsibus_write_data();
627
628               if(data_idx == 0 && bytes_left == 0)
629               {
630                  check_process_dataout();
631                  scsi_change_phase(SCSI_PHASE_STATUS);
632               }
633               else
634               {
635                  scsi_out( 0, SCSI_MASK_REQ );
636               }
637            }
638            else
639            {
640               scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ );
641            }
642         }
643         break;
644
645      case SCSI_PHASE_STATUS:
646         if( ( mask & SCSI_MASK_ACK ) != 0 )
647         {
648            if( ( data & SCSI_MASK_ACK ) != 0 )
649            {
650               if(cmd_idx > 0)
651               {
652                  scsi_change_phase(SCSI_PHASE_MESSAGE_IN);
653               }
654               else
655               {
656                  scsi_out( 0, SCSI_MASK_REQ );
657               }
658            }
659            else
660            {
661               cmd_idx++;
662               scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ );
663            }
664         }
665         break;
666
667      case SCSI_PHASE_MESSAGE_IN:
668         if( ( mask & SCSI_MASK_ACK ) != 0 )
669         {
670            if( ( data & SCSI_MASK_ACK ) != 0 )
671            {
672               if(cmd_idx > 0)
673               {
674                  if(is_linked)
675                     scsi_change_phase(SCSI_PHASE_COMMAND);
676                  else
677                     scsi_change_phase(SCSI_PHASE_BUS_FREE);
678               }
679               else
680               {
681                  scsi_out( 0, SCSI_MASK_REQ );
682               }
683            }
684            else
685            {
686               cmd_idx++;
687               scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ );
688            }
689         }
690         break;
691   }
692}
693
694void scsihle_device::check_process_dataout()
695{
696   int capacity=0;
697   int tracks;
698   adaptec_sense_t *sense;
699
700   LOG(1,"SCSIBUS:check_process_dataout cmd=%02X\n",command[0]);
701
702   switch (command[0])
703   {
704      case SCSI_CMD_MODE_SELECT:
705         sense=(adaptec_sense_t *)buffer;
706         tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1];
707         capacity=(tracks * sense->head_count * 17);
708         LOG(1,"Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track);
709         LOG(1,"Setting disk capacity to %d blocks\n",capacity);
710         dump_data_bytes(0x16);
711         break;
712   }
713}
714
715// get the length of a SCSI command based on it's command byte type
716int scsihle_device::get_scsi_cmd_len(int cbyte)
717{
718   int group;
719
720   group = (cbyte>>5) & 7;
721
722   if (group == 0 || group == 3 || group == 6 || group == 7) return 6;
723   if (group == 1 || group == 2) return 10;
724   if (group == 5) return 12;
725
726   fatalerror("scsihle: Unknown SCSI command group %d, command byte=%02X\n", group,cbyte);
727
728   return 6;
729}
trunk/src/emu/machine/scsihle.h
r18343r18344
1/***************************************************************************
1/*
22
3 scsihle.h
3scsihle.h
44
5***************************************************************************/
5Base class for HLE'd SCSI devices.
66
7*/
8
79#ifndef _SCSIHLE_H_
810#define _SCSIHLE_H_
911
12#include "machine/scsibus.h"
1013#include "machine/scsidev.h"
1114
12// base handler
1315class scsihle_device : public scsidev_device
1416{
1517public:
r18343r18344
2628   virtual void SetPhase( int phase );
2729   virtual void GetPhase( int *phase );
2830   virtual int GetDeviceID();
29   virtual int GetSectorBytes();
31   virtual int GetSectorBytes() = 0;
3032
33   virtual void scsi_in( UINT32 data, UINT32 mask );
34
3135   // configuration helpers
3236   static void static_set_deviceid(device_t &device, int _scsiID);
3337
3438protected:
3539   // device-level overrides
3640   virtual void device_start();
41   virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
3742
3843private:
39   UINT8 command[16];
44   void scsi_change_phase(UINT8 newphase);
45   int get_scsi_cmd_len(int cbyte);
46   UINT8 scsibus_driveno(UINT8  drivesel);
47   void scsibus_read_data();
48   void scsibus_write_data();
49   void scsibus_exec_command();
50   void check_process_dataout();
51   void dump_command_bytes();
52   void dump_data_bytes(int count);
53   void dump_bytes(UINT8 *buff, int count);
54
55   //emu_timer *req_timer;
56   //emu_timer *ack_timer;
57   emu_timer *sel_timer;
58   emu_timer *dataout_timer;
59
60   UINT8 command[ 32 ];
61   UINT8 cmd_idx;
62   UINT8 is_linked;
63
64   UINT8 buffer[ 1024 ];
65   UINT16 data_idx;
66   int bytes_left;
67   int data_last;
68   int sectorbytes;
69
4070   int commandLength;
4171   int phase;
4272   int scsiID;
r18343r18344
6494// Status / Sense data taken from Adaptec ACB40x0 documentation.
6595//
6696
67#define SCSI_STATUS_OK            0x00
68#define SCSI_STATUS_CHECK         0x02
69#define SCSI_STATUS_EQUAL         0x04
70#define SCSI_STATUS_BUSY         0x08
97#define SCSI_STATUS_OK              0x00
98#define SCSI_STATUS_CHECK           0x02
99#define SCSI_STATUS_EQUAL           0x04
100#define SCSI_STATUS_BUSY            0x08
71101
72#define SCSI_SENSE_ADDR_VALID      0x80
73#define SCSI_SENSE_NO_SENSE         0x00
74#define SCSI_SENSE_NO_INDEX         0x01
75#define SCSI_SENSE_SEEK_NOT_COMP   0x02
76#define SCSI_SENSE_WRITE_FAULT      0x03
77#define SCSI_SENSE_DRIVE_NOT_READY   0x04
78#define SCSI_SENSE_NO_TRACK0      0x06
79#define SCSI_SENSE_ID_CRC_ERROR      0x10
80#define SCSI_SENSE_UNCORRECTABLE   0x11
81#define SCSI_SENSE_ADDRESS_NF      0x12
82#define SCSI_SENSE_RECORD_NOT_FOUND   0x14
83#define SCSI_SENSE_SEEK_ERROR      0x15
84#define SCSI_SENSE_DATA_CHECK_RETRY   0x18
85#define SCSI_SENSE_ECC_VERIFY      0x19
86#define SCSI_SENSE_INTERLEAVE_ERROR   0x1A
87#define SCSI_SENSE_UNFORMATTED      0x1C
88#define SCSI_SENSE_ILLEGAL_COMMAND   0x20
89#define SCSI_SENSE_ILLEGAL_ADDRESS   0x21
90#define SCSI_SENSE_VOLUME_OVERFLOW   0x23
91#define SCSI_SENSE_BAD_ARGUMENT      0x24
92#define SCSI_SENSE_INVALID_LUN      0x25
93#define SCSI_SENSE_CART_CHANGED      0x28
94#define SCSI_SENSE_ERROR_OVERFLOW   0x2C
102#define SCSI_SENSE_ADDR_VALID       0x80
103#define SCSI_SENSE_NO_SENSE         0x00
104#define SCSI_SENSE_NO_INDEX         0x01
105#define SCSI_SENSE_SEEK_NOT_COMP    0x02
106#define SCSI_SENSE_WRITE_FAULT      0x03
107#define SCSI_SENSE_DRIVE_NOT_READY  0x04
108#define SCSI_SENSE_NO_TRACK0        0x06
109#define SCSI_SENSE_ID_CRC_ERROR     0x10
110#define SCSI_SENSE_UNCORRECTABLE    0x11
111#define SCSI_SENSE_ADDRESS_NF       0x12
112#define SCSI_SENSE_RECORD_NOT_FOUND 0x14
113#define SCSI_SENSE_SEEK_ERROR       0x15
114#define SCSI_SENSE_DATA_CHECK_RETRY 0x18
115#define SCSI_SENSE_ECC_VERIFY       0x19
116#define SCSI_SENSE_INTERLEAVE_ERROR 0x1A
117#define SCSI_SENSE_UNFORMATTED      0x1C
118#define SCSI_SENSE_ILLEGAL_COMMAND  0x20
119#define SCSI_SENSE_ILLEGAL_ADDRESS  0x21
120#define SCSI_SENSE_VOLUME_OVERFLOW  0x23
121#define SCSI_SENSE_BAD_ARGUMENT     0x24
122#define SCSI_SENSE_INVALID_LUN      0x25
123#define SCSI_SENSE_CART_CHANGED     0x28
124#define SCSI_SENSE_ERROR_OVERFLOW   0x2C
95125
96126// SCSI IDs
97127enum
trunk/src/emu/machine/scsicb.c
r18343r18344
1/*
2
3scsicb.c
4
5Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI
6controler chip such as the RM Nimbus, which implements it as a bunch of
774LS series chips.
8
9*/
10
111#include "scsicb.h"
212#include "scsibus.h"
313
r18343r18344
212scsicb_device::scsicb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
3    : device_t(mconfig, SCSICB, "SCSI callback", tag, owner, clock)
13    : scsidev_device(mconfig, SCSICB, "SCSI callback", tag, owner, clock)
414{
r18343r18344
1828
1929void scsicb_device::device_start()
2030{
31   scsidev_device::device_start();
32
2133   out_bsy_func.resolve(_out_bsy_func, *this);
2234   out_sel_func.resolve(_out_sel_func, *this);
2335   out_cd_func.resolve(_out_cd_func, *this);
r18343r18344
2941   out_rst_func.resolve(_out_rst_func, *this);
3042}
3143
44void scsicb_device::scsi_in( UINT32 data, UINT32 mask )
45{
46   linestate = data;
47
48   if( ( mask & SCSI_MASK_BSY ) != 0 )
49   {
50      out_bsy_func( (int) ( data & SCSI_MASK_BSY ) != 0 );
51   }
52
53   if( ( mask & SCSI_MASK_SEL ) != 0 )
54   {
55      out_sel_func( (int) ( data & SCSI_MASK_SEL ) != 0 );
56   }
57
58   if( ( mask & SCSI_MASK_CD ) != 0 )
59   {
60      out_cd_func( (int) ( data & SCSI_MASK_CD ) != 0 );
61   }
62
63   if( ( mask & SCSI_MASK_IO ) != 0 )
64   {
65      out_io_func( (int) ( data & SCSI_MASK_IO ) != 0 );
66   }
67
68   if( ( mask & SCSI_MASK_MSG ) != 0 )
69   {
70      out_msg_func( (int) ( data & SCSI_MASK_MSG ) != 0 );
71   }
72
73   if( ( mask & SCSI_MASK_REQ ) != 0 )
74   {
75      out_req_func( (int) ( data & SCSI_MASK_REQ ) != 0 );
76   }
77
78   if( ( mask & SCSI_MASK_ACK ) != 0 )
79   {
80      out_ack_func( (int) ( data & SCSI_MASK_ACK ) != 0 );
81   }
82
83   if( ( mask & SCSI_MASK_ATN ) != 0 )
84   {
85      out_ack_func( (int) ( data & SCSI_MASK_ATN ) != 0 );
86   }
87
88   if( ( mask & SCSI_MASK_RST ) != 0 )
89   {
90      out_rst_func( (int) ( data & SCSI_MASK_RST ) != 0 );
91   }
92}
93
3294UINT8 scsicb_device::scsi_data_r()
3395{
34   scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() );
35   return m_scsibus->scsi_data_r();
96   return linestate & SCSI_MASK_DATA;
3697}
3798
3899void scsicb_device::scsi_data_w( UINT8 data )
39100{
40   scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() );
41   m_scsibus->scsi_data_w( data );
101   scsi_out( data, SCSI_MASK_DATA );
42102}
43103
44UINT8 scsicb_device::get_scsi_line( UINT8 line )
104UINT8 scsicb_device::get_scsi_line( UINT32 line )
45105{
46   scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() );
47   return m_scsibus->get_scsi_line( line );
106   UINT8 result = (int)( ( linestate & line ) != 0 );
107
108//   LOG(3,"get_scsi_line(%s)=%d\n",linenames[lineno],result);
109
110   return result;
48111}
49112
50void scsicb_device::set_scsi_line( UINT8 line, UINT8 state )
113void scsicb_device::set_scsi_line( UINT32 mask, UINT8 state )
51114{
52   scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() );
53   m_scsibus->set_scsi_line( line, state );
115   scsi_out( state * mask, mask );
54116}
55117
56118READ8_MEMBER( scsicb_device::scsi_data_r )
r18343r18344
63125   scsi_data_w( data );
64126}
65127
66READ_LINE_MEMBER( scsicb_device::scsi_bsy_r ) { return get_scsi_line(SCSI_LINE_BSY); }
67READ_LINE_MEMBER( scsicb_device::scsi_sel_r ) { return get_scsi_line(SCSI_LINE_SEL); }
68READ_LINE_MEMBER( scsicb_device::scsi_cd_r ) { return get_scsi_line(SCSI_LINE_CD); }
69READ_LINE_MEMBER( scsicb_device::scsi_io_r ) { return get_scsi_line(SCSI_LINE_IO); }
70READ_LINE_MEMBER( scsicb_device::scsi_msg_r ) { return get_scsi_line(SCSI_LINE_MSG); }
71READ_LINE_MEMBER( scsicb_device::scsi_req_r ) { return get_scsi_line(SCSI_LINE_REQ); }
72READ_LINE_MEMBER( scsicb_device::scsi_ack_r ) { return get_scsi_line(SCSI_LINE_ACK); }
73READ_LINE_MEMBER( scsicb_device::scsi_atn_r ) { return get_scsi_line(SCSI_LINE_ATN); }
74READ_LINE_MEMBER( scsicb_device::scsi_rst_r ) { return get_scsi_line(SCSI_LINE_RST); }
128READ_LINE_MEMBER( scsicb_device::scsi_bsy_r ) { return get_scsi_line(SCSI_MASK_BSY); }
129READ_LINE_MEMBER( scsicb_device::scsi_sel_r ) { return get_scsi_line(SCSI_MASK_SEL); }
130READ_LINE_MEMBER( scsicb_device::scsi_cd_r ) { return get_scsi_line(SCSI_MASK_CD); }
131READ_LINE_MEMBER( scsicb_device::scsi_io_r ) { return get_scsi_line(SCSI_MASK_IO); }
132READ_LINE_MEMBER( scsicb_device::scsi_msg_r ) { return get_scsi_line(SCSI_MASK_MSG); }
133READ_LINE_MEMBER( scsicb_device::scsi_req_r ) { return get_scsi_line(SCSI_MASK_REQ); }
134READ_LINE_MEMBER( scsicb_device::scsi_ack_r ) { return get_scsi_line(SCSI_MASK_ACK); }
135READ_LINE_MEMBER( scsicb_device::scsi_atn_r ) { return get_scsi_line(SCSI_MASK_ATN); }
136READ_LINE_MEMBER( scsicb_device::scsi_rst_r ) { return get_scsi_line(SCSI_MASK_RST); }
75137
76WRITE_LINE_MEMBER( scsicb_device::scsi_bsy_w ) { set_scsi_line(SCSI_LINE_BSY, state); }
77WRITE_LINE_MEMBER( scsicb_device::scsi_sel_w ) { set_scsi_line(SCSI_LINE_SEL, state); }
78WRITE_LINE_MEMBER( scsicb_device::scsi_cd_w ) { set_scsi_line(SCSI_LINE_CD, state); }
79WRITE_LINE_MEMBER( scsicb_device::scsi_io_w ) { set_scsi_line(SCSI_LINE_IO, state); }
80WRITE_LINE_MEMBER( scsicb_device::scsi_msg_w ) { set_scsi_line(SCSI_LINE_MSG, state); }
81WRITE_LINE_MEMBER( scsicb_device::scsi_req_w ) { set_scsi_line(SCSI_LINE_REQ, state); }
82WRITE_LINE_MEMBER( scsicb_device::scsi_ack_w ) { set_scsi_line(SCSI_LINE_ACK, state); }
83WRITE_LINE_MEMBER( scsicb_device::scsi_atn_w ) { set_scsi_line(SCSI_LINE_ATN, state); }
84WRITE_LINE_MEMBER( scsicb_device::scsi_rst_w ) { set_scsi_line(SCSI_LINE_RST, state); }
138WRITE_LINE_MEMBER( scsicb_device::scsi_bsy_w ) { set_scsi_line(SCSI_MASK_BSY, state); }
139WRITE_LINE_MEMBER( scsicb_device::scsi_sel_w ) { set_scsi_line(SCSI_MASK_SEL, state); }
140WRITE_LINE_MEMBER( scsicb_device::scsi_cd_w ) { set_scsi_line(SCSI_MASK_CD, state); }
141WRITE_LINE_MEMBER( scsicb_device::scsi_io_w ) { set_scsi_line(SCSI_MASK_IO, state); }
142WRITE_LINE_MEMBER( scsicb_device::scsi_msg_w ) { set_scsi_line(SCSI_MASK_MSG, state); }
143WRITE_LINE_MEMBER( scsicb_device::scsi_req_w ) { set_scsi_line(SCSI_MASK_REQ, state); }
144WRITE_LINE_MEMBER( scsicb_device::scsi_ack_w ) { set_scsi_line(SCSI_MASK_ACK, state); }
145WRITE_LINE_MEMBER( scsicb_device::scsi_atn_w ) { set_scsi_line(SCSI_MASK_ATN, state); }
146WRITE_LINE_MEMBER( scsicb_device::scsi_rst_w ) { set_scsi_line(SCSI_MASK_RST, state); }
85147
86148const device_type SCSICB = &device_creator<scsicb_device>;
trunk/src/emu/machine/scsicb.h
r18343r18344
11/*
2    SCSICB.h
32
4    Callbacks from SCSI/SASI bus for machines that don't use a SCSI
5    controler chip such as the RM Nimbus, which implements it as a bunch of
6    74LS series chips.
3scsicb.h
74
5Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI
6controler chip such as the RM Nimbus, which implements it as a bunch of
774LS series chips.
8
89*/
910
1011#pragma once
r18343r18344
1213#ifndef _SCSICB_H_
1314#define _SCSICB_H_
1415
15#include "emu.h"
16#include "scsidev.h"
1617
17/***************************************************************************
18    MACROS
19***************************************************************************/
20
21#define MCFG_SCSICB_ADD(_tag, _intf) \
22   MCFG_DEVICE_ADD(_tag, SCSICB, 0) \
23   MCFG_DEVICE_CONFIG(_intf)
24
25
2618struct SCSICB_interface
2719{
2820   devcb_write_line _out_bsy_func;
r18343r18344
3628   devcb_write_line _out_rst_func;
3729};
3830
39class scsicb_device : public device_t,
31class scsicb_device : public scsidev_device,
4032                 public SCSICB_interface
4133{
4234public:
4335   // construction/destruction
4436   scsicb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
4537
46   devcb_resolved_write_line out_bsy_func;
47   devcb_resolved_write_line out_sel_func;
48   devcb_resolved_write_line out_cd_func;
49   devcb_resolved_write_line out_io_func;
50   devcb_resolved_write_line out_msg_func;
51   devcb_resolved_write_line out_req_func;
52   devcb_resolved_write_line out_ack_func;
53   devcb_resolved_write_line out_atn_func;
54   devcb_resolved_write_line out_rst_func;
38   virtual void scsi_in( UINT32 data, UINT32 mask );
5539
5640   UINT8 scsi_data_r();
5741   void scsi_data_w( UINT8 data );
5842
59   UINT8 get_scsi_line(UINT8 lineno);
60   void set_scsi_line(UINT8 line, UINT8 state);
61
6243   DECLARE_READ8_MEMBER( scsi_data_r );
6344   DECLARE_WRITE8_MEMBER( scsi_data_w );
6445
r18343r18344
8667   // device-level overrides
8768   virtual void device_config_complete();
8869   virtual void device_start();
70
71private:
72   devcb_resolved_write_line out_bsy_func;
73   devcb_resolved_write_line out_sel_func;
74   devcb_resolved_write_line out_cd_func;
75   devcb_resolved_write_line out_io_func;
76   devcb_resolved_write_line out_msg_func;
77   devcb_resolved_write_line out_req_func;
78   devcb_resolved_write_line out_ack_func;
79   devcb_resolved_write_line out_atn_func;
80   devcb_resolved_write_line out_rst_func;
81
82   UINT8 get_scsi_line(UINT32 mask);
83   void set_scsi_line(UINT32 mask, UINT8 state);
84
85   UINT32 linestate;
8986};
9087
88#define MCFG_SCSICB_ADD(_tag, _intf) \
89   MCFG_DEVICE_ADD(_tag, SCSICB, 0) \
90   MCFG_DEVICE_CONFIG(_intf)
91
9192// device type definition
9293extern const device_type SCSICB;
9394
trunk/src/emu/machine/scsidev.c
r18343r18344
1/***************************************************************************
1/*
22
3 scsidev.c - Base class for SCSI devices.
3scsidev.c
44
5***************************************************************************/
5Base class for SCSI devices.
66
7*/
8
9#include "machine/scsibus.h"
710#include "machine/scsidev.h"
811
912scsidev_device::scsidev_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
1013   device_t(mconfig, type, name, tag, owner, clock)
1114{
1215}
16
17void scsidev_device::device_start()
18{
19   data_out = SCSI_MASK_ALL;
20}
21
22void scsidev_device::scsi_out( UINT32 data, UINT32 mask )
23{
24   data_out = ( data_out & ~mask ) | ( data & mask );
25
26   scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() );
27   m_scsibus->scsi_update();
28}
trunk/src/emu/machine/scsidev.h
r18343r18344
1/***************************************************************************
1/*
22
3 scsidev.h
3scsidev.h
44
5***************************************************************************/
5Base class for SCSI devices.
66
7*/
8
79#ifndef _SCSIDEV_H_
810#define _SCSIDEV_H_
911
1012#include "emu.h"
1113
14#define SCSI_MASK_DATA  ( 0x00000ff )
15#define SCSI_MASK_DATAH ( 0x000ff00 )
16#define SCSI_MASK_DATAP ( 0x0010000 )
17#define SCSI_MASK_BSY   ( 0x0020000 )
18#define SCSI_MASK_SEL   ( 0x0040000 )
19#define SCSI_MASK_CD    ( 0x0080000 )
20#define SCSI_MASK_IO    ( 0x0100000 )
21#define SCSI_MASK_MSG   ( 0x0200000 )
22#define SCSI_MASK_REQ   ( 0x0400000 )
23#define SCSI_MASK_ACK   ( 0x0800000 )
24#define SCSI_MASK_ATN   ( 0x1000000 )
25#define SCSI_MASK_RST   ( 0x2000000 )
26#define SCSI_MASK_ALL   ( 0x3ffffff )
27
1228// base handler
1329class scsidev_device : public device_t
1430{
1531public:
1632   // construction/destruction
1733   scsidev_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
34
35   virtual void scsi_in( UINT32 data, UINT32 mask ) = 0;
36   void scsi_out( UINT32 data, UINT32 mask );
37
38   UINT32 data_out;
39
40protected:
41   // device-level overrides
42   virtual void device_start();
1843};
1944
2045#endif

Previous 199869 Revisions Next


© 1997-2024 The MAME Team