|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
26: *
27: * SCSIGenericKern.m - UNIX front end for SCSIGeneric device.
28: *
29: * HISTORY
30: * 19-Aug-91 Doug Mitchell at NeXT
31: * Created.
32: */
33:
34: /*
35: * Note that this file builds with KERNEL_PRIVATE and !MACH_USER_API.
36: */
37: #import <sys/param.h>
38: #import <sys/proc.h>
39: #import <sys/user.h>
40: #import <bsd/dev/scsireg.h>
41:
42: #import <vm/vm_kern.h>
43:
44: #import <driverkit/SCSIGeneric.h>
45: #import <driverkit/SCSIGenericPrivate.h>
46: #import <driverkit/scsiTypes.h>
47: #import <driverkit/xpr_mi.h>
48: #import <driverkit/align.h>
49: #import <kernserv/ns_timer.h>
50:
51: /*
52: * Map minor number to an id of a SCSIGeneric instance.
53: */
54: id sgIdMap[NUM_SG_DEV];
55:
56: /*
57: * Index of our entry in cdevsw.
58: */
59: static int sg_major;
60:
61: /*
62: * prototypes of static functions.
63: */
64: static id sgDevToId(dev_t dev);
65: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp);
66:
67: /*
68: * cdevsw callouts.
69: */
70:
71: int sgopen(dev_t dev,
72: int oflags,
73: int devtype,
74: struct proc *pp)
75: {
76: id devId = sgDevToId(dev);
77:
78: xpr_sdev("sgopen: unit %d\n", minor(dev), 2,3,4,5);
79: if(devId == nil) {
80: return ENXIO;
81: }
82:
83: /*
84: * Note we use devId as "caller" since we're not an object; this
85: * works since "caller" isn't used for any authentication.
86: */
87: if([devId acquire:devId]) {
88: return EBUSY;
89: }
90: else {
91: return 0;
92: }
93: }
94:
95: int sgclose(dev_t dev,
96: int fflag,
97: int devtype,
98: struct proc *pp)
99: {
100: id devId = sgDevToId(dev);
101:
102: xpr_sdev("sgclose: unit %d\n", minor(dev), 2,3,4,5);
103: if(devId == nil) {
104: return ENXIO;
105: }
106: [devId release:devId];
107: }
108:
109: #define SCSI3_DEBUG 0
110:
111: int
112: sgioctl(dev_t dev,
113: u_long cmd, /* SGIOCREQ, etc */
114: caddr_t data, /* actually a ptr to scsi_req, if used */
115: int flag, /* for historical reasons. Not used. */
116: struct proc *p)
117: {
118: id devId = sgDevToId(dev);
119:
120: scsi_req_t *srp = (scsi_req_t *)data;
121: scsi_adr_t *sap = (scsi_adr_t *)data;
122: scsi3_req_t *s3rp = (scsi3_req_t *)data;
123: scsi3_adr_t *s3ap = (scsi3_adr_t *)data;
124: int rtn = 0;
125:
126: xpr_sdev("sgioctl: unit %d\n", minor(dev), 2,3,4,5);
127: if(devId == nil) {
128: return ENXIO;
129: }
130: switch (cmd) {
131: case SGIOCSTL: /* set target/lun */
132: if([devId setTarget:sap->sa_target
133: lun:sap->sa_lun
134: isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) {
135: rtn = EACCES;
136: }
137: break;
138:
139: case SGIOCCNTR:
140: if([devId setController:*(int *)data]) {
141: rtn = ENODEV;
142: }
143: break;
144:
145: case SGIOCSTL3: /* set SCSI3 target/lun */
146: #if SCSI3_DEBUG
147: IOLog("SGIOCSTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n",
148: (unsigned)(s3ap->s3a_target >> 32),
149: (unsigned)(s3ap->s3a_target),
150: (unsigned)(s3ap->s3a_lun >> 32),
151: (unsigned)(s3ap->s3a_lun));
152: #endif SCSI3_DEBUG
153: if([devId setSCSI3Target:s3ap->s3a_target
154: lun:s3ap->s3a_lun
155: isRoot:suser(p->p_ucred, &p->p_acflag) ? 0 : 1]) {
156: rtn = EACCES;
157: }
158: break;
159:
160: case SGIOCGTL3:
161: s3ap->s3a_target = [devId SCSI3_target];
162: s3ap->s3a_lun = [devId SCSI3_lun];
163: #if SCSI3_DEBUG
164: IOLog("SGIOCGTL3: s3a_target = 0x%x:%x s3a_lun = 0x%x:%x\n",
165: (unsigned)(s3ap->s3a_target >> 32),
166: (unsigned)(s3ap->s3a_target),
167: (unsigned)(s3ap->s3a_lun >> 32),
168: (unsigned)(s3ap->s3a_lun));
169: #endif SCSI3_DEBUG
170: break;
171:
172: case SGIOCREQ:
173: rtn = sg_doiocreq(devId, srp, NULL);
174: break;
175:
176: case SGIOCREQ3:
177: rtn = sg_doiocreq(devId, NULL, s3rp);
178: break;
179:
180: case SGIOCENAS: /* enable auto sense */
181: if([devId enableAutoSense]) {
182: rtn = EINVAL;
183: }
184: break;
185:
186: case SGIOCDAS: /* disable auto sense */
187: if([devId disableAutoSense]) {
188: rtn = EINVAL;
189: }
190: break;
191:
192: case SGIOCGAS:
193: *(int *)data = ([devId autoSense] ? 1 : 0);
194: break;
195:
196: case SGIOCMAXDMA:
197: *(int *)data = [[devId controller] maxTransfer];
198: break;
199:
200: case SGIOCNUMTARGS:
201: *(int *)data = [[devId controller] numberOfTargets];
202: break;
203:
204: case SGIOCRST:
205: #ifndef DEBUG
206: if (suser(p->p_ucred, &p->p_acflag)) {
207: /* this is too dangerous for
208: * the hoi polloi */
209: rtn = EPERM;
210: break;
211: }
212: #endif DEBUG
213: if([devId resetSCSIBus]) { /* what could go wrong? */
214: rtn = EIO;
215: }
216: break;
217:
218: default:
219: rtn = EINVAL;
220: }
221: xpr_sdev("sgioctl: returning %d\n", rtn, 2,3,4,5);
222: return rtn;
223: } /* sgioctl() */
224:
225: /*
226: * Static functions.
227: */
228:
229: /*
230: * Obtain id for SCSIGeneric instance associated with specified dev_t.
231: * A return of nil indicates ENXIO.
232: */
233: static id sgDevToId(dev_t dev)
234: {
235: int minor = minor(dev);
236:
237: if((minor < 0) || (minor >= NUM_SG_DEV)) {
238: return nil;
239: }
240: return sgIdMap[minor];
241: }
242:
243: /*
244: * Execute one scsi_req. Called from client's task context. Returns an errno.
245: * Exactly one of srp and s3rp must be non-NULL.
246: */
247:
248: /*
249: * FIXME - DMA to non-page-aligned user memory doesn't work. There
250: * is data corruption on read operations;l the corruption occurs on page
251: * boundaries.
252: */
253: #define FORCE_PAGE_ALIGN 1
254: #if FORCE_PAGE_ALIGN
255: int forcePageAlign = 1;
256: #endif FORCE_PAGE_ALIGN
257:
258: static int sg_doiocreq(id devId, scsi_req_t *srp, scsi3_req_t *s3rp)
259: {
260: void *alignedPtr;
261: unsigned alignedLen = 0;
262: void *freePtr;
263: unsigned freeLen;
264: BOOL didAlign = NO;
265: vm_task_t client = NULL;
266: int rtn = 0;
267: sc_status_t srtn;
268: int dma_max;
269: sc_dma_dir_t dma_dir;
270: caddr_t dma_addr;
271: unsigned bytesTransferred;
272:
273: if(srp) {
274: dma_max = srp->sr_dma_max;
275: dma_dir = srp->sr_dma_dir;
276: dma_addr = srp->sr_addr;
277: }
278: else if(s3rp) {
279: dma_max = s3rp->s3r_dma_max;
280: dma_dir = s3rp->s3r_dma_dir;
281: dma_addr = s3rp->s3r_addr;
282: }
283: else {
284: IOPanic("sg_doiocreq: no scsi_req ptr");
285: }
286: if(dma_max > [[devId controller] maxTransfer]) {
287: return EINVAL;
288: }
289:
290: /* Get some well-aligned memory if necessary. By using
291: * allocateBufferOfLength we guarantee that there is enough space
292: * in the buffer we pass to the controller to handle
293: * end-of-buffer alignment, although we won't copy more
294: * than sr_dma_max to or from the caller.
295: */
296: if(dma_max != 0) {
297:
298: IODMAAlignment dmaAlign;
299: id controller = [devId controller];
300: unsigned alignLength;
301: unsigned alignStart;
302:
303: /*
304: * Get appropriate alignment from controller.
305: */
306: [controller getDMAAlignment:&dmaAlign];
307: if(dma_dir == SR_DMA_WR) {
308: alignLength = dmaAlign.writeLength;
309: alignStart = dmaAlign.writeStart;
310: }
311: else {
312: alignLength = dmaAlign.readLength;
313: alignStart = dmaAlign.readStart;
314: }
315: #if FORCE_PAGE_ALIGN
316: if(forcePageAlign) {
317: alignStart = PAGE_SIZE;
318: }
319: #endif FORCE_PAGE_ALIGN
320: if (1) { /* XXX fix the well aligned case for 3.3 */
321:
322: /*
323: * DMA from kernel memory, we allocate and copy.
324: */
325:
326: didAlign = YES;
327: client = kernel_map;
328:
329: if(alignLength > 1) {
330: alignedLen = IOAlign(unsigned,
331: dma_max,
332: alignLength);
333: }
334: else {
335: alignedLen = dma_max;
336: }
337: alignedPtr = [controller allocateBufferOfLength:
338: dma_max
339: actualStart:&freePtr
340: actualLength:&freeLen];
341: if(dma_dir == SR_DMA_WR) {
342: rtn = copyin(dma_addr, alignedPtr, dma_max);
343: if(rtn) {
344: xpr_sd(" ...copyin() returned %d\n",
345: rtn, 2,3,4,5);
346: rtn = EFAULT;
347: goto err_exit;
348: }
349: }
350: }
351: else {
352: /*
353: * Well-aligned buffer, DMA directly to/from user
354: * space.
355: */
356: alignedLen = dma_max;
357: alignedPtr = dma_addr;
358: client = current_task()->map;
359: didAlign = NO;
360: }
361:
362: } else {
363: alignedPtr = dma_addr;
364: }
365:
366:
367: /*
368: * Generate a contemporary version of scsi_req.
369: */
370: if(srp) {
371: IOSCSIRequest scsiReq;
372: unsigned long long addr;
373:
374: bzero(&scsiReq, sizeof(scsiReq));
375: addr = [devId SCSI3_target];
376:
377: /*
378: * Can only deal with SCSI-2 style addressing
379: * (32 targets, 8 LUNs).
380: */
381: if(addr >= SCSI3_NTARGETS) {
382: rtn = EINVAL;
383: goto err_exit;
384: }
385: scsiReq.target = (unsigned char)addr;
386: addr = [devId SCSI3_lun];
387: if(addr >= SCSI_NLUNS) {
388: rtn = EINVAL;
389: goto err_exit;
390: }
391: scsiReq.lun = (unsigned char)addr;
392:
393: /*
394: * Careful. this assumes that the old and new cdb structs are
395: * equivalent...
396: */
397: scsiReq.cdb = srp->sr_cdb;
398: scsiReq.read = (srp->sr_dma_dir == SR_DMA_RD)
399: ? YES : NO;
400: scsiReq.maxTransfer = alignedLen;
401: scsiReq.timeoutLength = srp->sr_ioto;
402: scsiReq.disconnect = srp->sr_discon_disable ? 0 : 1;
403: scsiReq.cmdQueueDisable = srp->sr_cmd_queue_disable;
404: scsiReq.syncDisable = srp->sr_sync_disable;
405: scsiReq.cdbLength = srp->sr_cdb_length;
406:
407:
408: /*
409: * Go for it.
410: */
411: srtn = [devId executeRequest : &scsiReq
412: buffer : alignedPtr
413: client : client
414: senseBuf : &srp->sr_esense];
415:
416: /*
417: * Copy status back to user. Note that if we got this far, we
418: * return good status from the function; errors are in
419: * srp->sr_io_status.
420: */
421: srp->sr_io_status = srtn;
422: srp->sr_scsi_status = scsiReq.scsiStatus;
423: bytesTransferred = srp->sr_dma_xfr = scsiReq.bytesTransferred;
424: if(srp->sr_dma_xfr > srp->sr_dma_max) {
425: srp->sr_dma_xfr = srp->sr_dma_max;
426: }
427: ns_time_to_timeval(scsiReq.totalTime, &srp->sr_exec_time);
428: }
429: else {
430: IOSCSI3Request scsi3Req;
431:
432: bzero(&scsi3Req, sizeof(scsi3Req));
433: scsi3Req.target = [devId SCSI3_target];
434: scsi3Req.lun = [devId SCSI3_lun];
435:
436: /*
437: * Careful. this assumes that the old and new cdb structs are
438: * equivalent...
439: */
440: scsi3Req.cdb = s3rp->s3r_cdb;
441: scsi3Req.read = (s3rp->s3r_dma_dir == SR_DMA_RD)
442: ? YES : NO;
443: scsi3Req.maxTransfer = alignedLen;
444: scsi3Req.timeoutLength = s3rp->s3r_ioto;
445: scsi3Req.disconnect = s3rp->s3r_discon_disable ? 0 : 1;
446: scsi3Req.cmdQueueDisable = s3rp->s3r_cmd_queue_disable;
447: scsi3Req.syncDisable = s3rp->s3r_sync_disable;
448: scsi3Req.cdbLength = s3rp->s3r_cdb_length;
449:
450:
451: /*
452: * Go for it.
453: */
454: srtn = [devId executeSCSI3Request : &scsi3Req
455: buffer : alignedPtr
456: client : client
457: senseBuf : &srp->sr_esense];
458:
459: /*
460: * Copy status back to user. Note that if we got this far, we
461: * return good status from the function; errors are in
462: * s3rp->sr_io_status.
463: */
464: s3rp->s3r_io_status = srtn;
465: s3rp->s3r_scsi_status = scsi3Req.scsiStatus;
466: bytesTransferred = s3rp->s3r_dma_xfr = scsi3Req.bytesTransferred;
467: if(s3rp->s3r_dma_xfr > s3rp->s3r_dma_max) {
468: s3rp->s3r_dma_xfr = s3rp->s3r_dma_max;
469: }
470: ns_time_to_timeval(scsi3Req.totalTime, &s3rp->s3r_exec_time);
471: }
472:
473: /*
474: * Copy read data back to user if appropriate.
475: */
476: if((dma_dir == SR_DMA_RD) &&
477: (bytesTransferred != 0) &&
478: didAlign) {
479: rtn = copyout(alignedPtr, dma_addr, bytesTransferred);
480: }
481: err_exit:
482: if(didAlign) {
483: IOFree(freePtr, freeLen);
484: }
485: return rtn;
486: }
487:
488:
489:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.